summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt7
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt4
-rw-r--r--src/android/app/src/main/jni/applets/software_keyboard.cpp12
-rw-r--r--src/android/app/src/main/jni/applets/software_keyboard.h4
-rw-r--r--src/android/app/src/main/jni/native.cpp45
-rw-r--r--src/android/app/src/main/jni/native.h5
-rw-r--r--src/audio_core/CMakeLists.txt4
-rw-r--r--src/common/CMakeLists.txt5
-rw-r--r--src/common/range_mutex.h93
-rw-r--r--src/common/settings.h12
-rw-r--r--src/core/CMakeLists.txt114
-rw-r--r--src/core/core.cpp86
-rw-r--r--src/core/core.h25
-rw-r--r--src/core/device_memory_manager.h18
-rw-r--r--src/core/device_memory_manager.inc63
-rw-r--r--src/core/frontend/applets/general.cpp (renamed from src/core/frontend/applets/general_frontend.cpp)2
-rw-r--r--src/core/frontend/applets/general.h (renamed from src/core/frontend/applets/general_frontend.h)0
-rw-r--r--src/core/frontend/applets/profile_select.h8
-rw-r--r--src/core/frontend/applets/software_keyboard.cpp12
-rw-r--r--src/core/frontend/applets/software_keyboard.h22
-rw-r--r--src/core/frontend/applets/web_browser.cpp4
-rw-r--r--src/core/frontend/applets/web_browser.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp30
-rw-r--r--src/core/hle/service/am/am.cpp2685
-rw-r--r--src/core/hle/service/am/am.h454
-rw-r--r--src/core/hle/service/am/am_results.h16
-rw-r--r--src/core/hle/service/am/am_types.h178
-rw-r--r--src/core/hle/service/am/applet.cpp27
-rw-r--r--src/core/hle/service/am/applet.h133
-rw-r--r--src/core/hle/service/am/applet_ae.cpp320
-rw-r--r--src/core/hle/service/am/applet_ae.h10
-rw-r--r--src/core/hle/service/am/applet_common_functions.cpp63
-rw-r--r--src/core/hle/service/am/applet_common_functions.h24
-rw-r--r--src/core/hle/service/am/applet_data_broker.cpp67
-rw-r--r--src/core/hle/service/am/applet_data_broker.h80
-rw-r--r--src/core/hle/service/am/applet_manager.cpp361
-rw-r--r--src/core/hle/service/am/applet_manager.h59
-rw-r--r--src/core/hle/service/am/applet_message_queue.cpp73
-rw-r--r--src/core/hle/service/am/applet_message_queue.h76
-rw-r--r--src/core/hle/service/am/applet_oe.cpp129
-rw-r--r--src/core/hle/service/am/applet_oe.h10
-rw-r--r--src/core/hle/service/am/applets/applets.cpp338
-rw-r--r--src/core/hle/service/am/applets/applets.h289
-rw-r--r--src/core/hle/service/am/application_creator.cpp25
-rw-r--r--src/core/hle/service/am/application_creator.h16
-rw-r--r--src/core/hle/service/am/application_functions.cpp594
-rw-r--r--src/core/hle/service/am/application_functions.h58
-rw-r--r--src/core/hle/service/am/application_proxy.cpp115
-rw-r--r--src/core/hle/service/am/application_proxy.h33
-rw-r--r--src/core/hle/service/am/audio_controller.cpp91
-rw-r--r--src/core/hle/service/am/audio_controller.h36
-rw-r--r--src/core/hle/service/am/common_state_getter.cpp314
-rw-r--r--src/core/hle/service/am/common_state_getter.h77
-rw-r--r--src/core/hle/service/am/debug_functions.cpp44
-rw-r--r--src/core/hle/service/am/debug_functions.h16
-rw-r--r--src/core/hle/service/am/display_controller.cpp135
-rw-r--r--src/core/hle/service/am/display_controller.h30
-rw-r--r--src/core/hle/service/am/frontend/applet_cabinet.cpp (renamed from src/core/hle/service/am/applets/applet_cabinet.cpp)29
-rw-r--r--src/core/hle/service/am/frontend/applet_cabinet.h (renamed from src/core/hle/service/am/applets/applet_cabinet.h)13
-rw-r--r--src/core/hle/service/am/frontend/applet_controller.cpp (renamed from src/core/hle/service/am/applets/applet_controller.cpp)31
-rw-r--r--src/core/hle/service/am/frontend/applet_controller.h (renamed from src/core/hle/service/am/applets/applet_controller.h)13
-rw-r--r--src/core/hle/service/am/frontend/applet_error.cpp (renamed from src/core/hle/service/am/applets/applet_error.cpp)23
-rw-r--r--src/core/hle/service/am/frontend/applet_error.h (renamed from src/core/hle/service/am/applets/applet_error.h)14
-rw-r--r--src/core/hle/service/am/frontend/applet_general.cpp (renamed from src/core/hle/service/am/applets/applet_general_backend.cpp)90
-rw-r--r--src/core/hle/service/am/frontend/applet_general.h (renamed from src/core/hle/service/am/applets/applet_general_backend.h)27
-rw-r--r--src/core/hle/service/am/frontend/applet_mii_edit.cpp (renamed from src/core/hle/service/am/applets/applet_mii_edit.cpp)27
-rw-r--r--src/core/hle/service/am/frontend/applet_mii_edit.h (renamed from src/core/hle/service/am/applets/applet_mii_edit.h)15
-rw-r--r--src/core/hle/service/am/frontend/applet_mii_edit_types.h (renamed from src/core/hle/service/am/applets/applet_mii_edit_types.h)4
-rw-r--r--src/core/hle/service/am/frontend/applet_profile_select.cpp (renamed from src/core/hle/service/am/applets/applet_profile_select.cpp)28
-rw-r--r--src/core/hle/service/am/frontend/applet_profile_select.h (renamed from src/core/hle/service/am/applets/applet_profile_select.h)13
-rw-r--r--src/core/hle/service/am/frontend/applet_software_keyboard.cpp (renamed from src/core/hle/service/am/applets/applet_software_keyboard.cpp)68
-rw-r--r--src/core/hle/service/am/frontend/applet_software_keyboard.h (renamed from src/core/hle/service/am/applets/applet_software_keyboard.h)15
-rw-r--r--src/core/hle/service/am/frontend/applet_software_keyboard_types.h (renamed from src/core/hle/service/am/applets/applet_software_keyboard_types.h)4
-rw-r--r--src/core/hle/service/am/frontend/applet_web_browser.cpp (renamed from src/core/hle/service/am/applets/applet_web_browser.cpp)24
-rw-r--r--src/core/hle/service/am/frontend/applet_web_browser.h (renamed from src/core/hle/service/am/applets/applet_web_browser.h)17
-rw-r--r--src/core/hle/service/am/frontend/applet_web_browser_types.h (renamed from src/core/hle/service/am/applets/applet_web_browser_types.h)4
-rw-r--r--src/core/hle/service/am/frontend/applets.cpp240
-rw-r--r--src/core/hle/service/am/frontend/applets.h146
-rw-r--r--src/core/hle/service/am/global_state_controller.cpp34
-rw-r--r--src/core/hle/service/am/global_state_controller.h16
-rw-r--r--src/core/hle/service/am/hid_registration.cpp35
-rw-r--r--src/core/hle/service/am/hid_registration.h32
-rw-r--r--src/core/hle/service/am/home_menu_functions.cpp57
-rw-r--r--src/core/hle/service/am/home_menu_functions.h25
-rw-r--r--src/core/hle/service/am/library_applet_accessor.cpp202
-rw-r--r--src/core/hle/service/am/library_applet_accessor.h43
-rw-r--r--src/core/hle/service/am/library_applet_creator.cpp271
-rw-r--r--src/core/hle/service/am/library_applet_creator.h26
-rw-r--r--src/core/hle/service/am/library_applet_proxy.cpp143
-rw-r--r--src/core/hle/service/am/library_applet_proxy.h36
-rw-r--r--src/core/hle/service/am/library_applet_self_accessor.cpp338
-rw-r--r--src/core/hle/service/am/library_applet_self_accessor.h44
-rw-r--r--src/core/hle/service/am/library_applet_storage.cpp140
-rw-r--r--src/core/hle/service/am/library_applet_storage.h36
-rw-r--r--src/core/hle/service/am/lock_accessor.cpp71
-rw-r--r--src/core/hle/service/am/lock_accessor.h28
-rw-r--r--src/core/hle/service/am/managed_layer_holder.cpp59
-rw-r--r--src/core/hle/service/am/managed_layer_holder.h32
-rw-r--r--src/core/hle/service/am/process.cpp138
-rw-r--r--src/core/hle/service/am/process.h50
-rw-r--r--src/core/hle/service/am/process_winding_controller.cpp56
-rw-r--r--src/core/hle/service/am/process_winding_controller.h24
-rw-r--r--src/core/hle/service/am/self_controller.cpp456
-rw-r--r--src/core/hle/service/am/self_controller.h58
-rw-r--r--src/core/hle/service/am/storage.cpp59
-rw-r--r--src/core/hle/service/am/storage.h31
-rw-r--r--src/core/hle/service/am/storage_accessor.cpp90
-rw-r--r--src/core/hle/service/am/storage_accessor.h37
-rw-r--r--src/core/hle/service/am/system_applet_proxy.cpp136
-rw-r--r--src/core/hle/service/am/system_applet_proxy.h36
-rw-r--r--src/core/hle/service/am/system_buffer_manager.cpp69
-rw-r--r--src/core/hle/service/am/system_buffer_manager.h51
-rw-r--r--src/core/hle/service/am/window_controller.cpp86
-rw-r--r--src/core/hle/service/am/window_controller.h27
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp2
-rw-r--r--src/core/hle/service/caps/caps_manager.cpp12
-rw-r--r--src/core/hle/service/cmif_serialization.h177
-rw-r--r--src/core/hle/service/cmif_types.h197
-rw-r--r--src/core/hle/service/event.cpp31
-rw-r--r--src/core/hle/service/event.h31
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp48
-rw-r--r--src/core/hle/service/glue/time/alarm_worker.cpp3
-rw-r--r--src/core/hle/service/glue/time/alarm_worker.h4
-rw-r--r--src/core/hle/service/glue/time/file_timestamp_worker.cpp4
-rw-r--r--src/core/hle/service/glue/time/manager.cpp40
-rw-r--r--src/core/hle/service/glue/time/static.cpp394
-rw-r--r--src/core/hle/service/glue/time/static.h76
-rw-r--r--src/core/hle/service/glue/time/time_zone.cpp352
-rw-r--r--src/core/hle/service/glue/time/time_zone.h67
-rw-r--r--src/core/hle/service/glue/time/time_zone_binary.cpp11
-rw-r--r--src/core/hle/service/glue/time/time_zone_binary.h2
-rw-r--r--src/core/hle/service/glue/time/worker.cpp42
-rw-r--r--src/core/hle/service/glue/time/worker.h8
-rw-r--r--src/core/hle/service/hid/hid_server.cpp45
-rw-r--r--src/core/hle/service/hid/hid_server.h5
-rw-r--r--src/core/hle/service/mii/mii.cpp15
-rw-r--r--src/core/hle/service/nfc/common/device.cpp8
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp8
-rw-r--r--src/core/hle/service/nifm/nifm.cpp12
-rw-r--r--src/core/hle/service/ns/ns.cpp67
-rw-r--r--src/core/hle/service/ns/ns.h15
-rw-r--r--src/core/hle/service/nvdrv/core/container.cpp4
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp2
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.cpp10
-rw-r--r--src/core/hle/service/nvnflinger/nvnflinger.h3
-rw-r--r--src/core/hle/service/psc/time/common.h135
-rw-r--r--src/core/hle/service/psc/time/power_state_service.cpp28
-rw-r--r--src/core/hle/service/psc/time/power_state_service.h7
-rw-r--r--src/core/hle/service/psc/time/service_manager.cpp450
-rw-r--r--src/core/hle/service/psc/time/service_manager.h60
-rw-r--r--src/core/hle/service/psc/time/static.cpp493
-rw-r--r--src/core/hle/service/psc/time/static.h65
-rw-r--r--src/core/hle/service/psc/time/steady_clock.cpp133
-rw-r--r--src/core/hle/service/psc/time/steady_clock.h21
-rw-r--r--src/core/hle/service/psc/time/system_clock.cpp92
-rw-r--r--src/core/hle/service/psc/time/system_clock.h13
-rw-r--r--src/core/hle/service/psc/time/time_zone.cpp51
-rw-r--r--src/core/hle/service/psc/time/time_zone.h17
-rw-r--r--src/core/hle/service/psc/time/time_zone_service.cpp318
-rw-r--r--src/core/hle/service/psc/time/time_zone_service.h57
-rw-r--r--src/core/hle/service/set/setting_formats/system_settings.cpp2
-rw-r--r--src/core/hle/service/set/system_settings_server.cpp2
-rw-r--r--src/core/hle/service/sockets/sockets.h1
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp2
-rw-r--r--src/core/hle/service/vi/display/vi_display.cpp4
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.cpp2
-rw-r--r--src/core/hle/service/vi/layer/vi_layer.h9
-rw-r--r--src/core/hle/service/vi/vi.cpp8
-rw-r--r--src/core/internal_network/network.cpp32
-rw-r--r--src/core/internal_network/sockets.h3
-rw-r--r--src/dedicated_room/CMakeLists.txt4
-rw-r--r--src/hid_core/CMakeLists.txt1
-rw-r--r--src/hid_core/hid_types.h15
-rw-r--r--src/hid_core/resources/npad/npad.cpp11
-rw-r--r--src/hid_core/resources/npad/npad.h2
-rw-r--r--src/hid_core/resources/shared_memory_format.h13
-rw-r--r--src/hid_core/resources/system_buttons/capture_button.cpp26
-rw-r--r--src/hid_core/resources/system_buttons/capture_button.h3
-rw-r--r--src/hid_core/resources/system_buttons/home_button.cpp26
-rw-r--r--src/hid_core/resources/system_buttons/home_button.h3
-rw-r--r--src/hid_core/resources/system_buttons/sleep_button.cpp23
-rw-r--r--src/hid_core/resources/system_buttons/sleep_button.h3
-rw-r--r--src/hid_core/resources/system_buttons/system_button_types.h31
-rw-r--r--src/hid_core/resources/unique_pad/unique_pad.cpp2
-rw-r--r--src/video_core/CMakeLists.txt6
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp5
-rw-r--r--src/video_core/texture_cache/texture_cache.h87
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h4
-rw-r--r--src/video_core/vulkan_common/vk_enum_string_helper.h8
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp107
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.h3
-rw-r--r--src/yuzu/CMakeLists.txt4
-rw-r--r--src/yuzu/applets/qt_profile_select.cpp4
-rw-r--r--src/yuzu/applets/qt_software_keyboard.cpp10
-rw-r--r--src/yuzu/applets/qt_software_keyboard.h17
-rw-r--r--src/yuzu/applets/qt_web_browser.cpp12
-rw-r--r--src/yuzu/applets/qt_web_browser.h10
-rw-r--r--src/yuzu/configuration/configure_audio.cpp117
-rw-r--r--src/yuzu/configuration/configure_audio.h7
-rw-r--r--src/yuzu/configuration/configure_input.cpp18
-rw-r--r--src/yuzu/game_list.cpp12
-rw-r--r--src/yuzu/game_list.h3
-rw-r--r--src/yuzu/main.cpp168
-rw-r--r--src/yuzu/main.h38
-rw-r--r--src/yuzu_cmd/CMakeLists.txt4
-rw-r--r--src/yuzu_cmd/yuzu.cpp6
207 files changed, 8861 insertions, 7126 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 53137b2e2..6ebb46af7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -261,7 +261,7 @@ object NativeLibrary {
261 /** 261 /**
262 * Begins emulation. 262 * Begins emulation.
263 */ 263 */
264 external fun run(path: String?, programIndex: Int = 0) 264 external fun run(path: String?, programIndex: Int, frontendInitiated: Boolean)
265 265
266 // Surface Handling 266 // Surface Handling
267 external fun surfaceChanged(surf: Surface?) 267 external fun surfaceChanged(surf: Surface?)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
index d6f17cf29..f218c76ef 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/DriverAdapter.kt
@@ -7,6 +7,7 @@ import android.text.TextUtils
7import android.view.LayoutInflater 7import android.view.LayoutInflater
8import android.view.View 8import android.view.View
9import android.view.ViewGroup 9import android.view.ViewGroup
10import org.yuzu.yuzu_emu.R
10import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding 11import org.yuzu.yuzu_emu.databinding.CardDriverOptionBinding
11import org.yuzu.yuzu_emu.features.settings.model.StringSetting 12import org.yuzu.yuzu_emu.features.settings.model.StringSetting
12import org.yuzu.yuzu_emu.model.Driver 13import org.yuzu.yuzu_emu.model.Driver
@@ -57,13 +58,9 @@ class DriverAdapter(private val driverViewModel: DriverViewModel) :
57 title.text = model.title 58 title.text = model.title
58 version.text = model.version 59 version.text = model.version
59 description.text = model.description 60 description.text = model.description
60 if (model.description.isNotEmpty()) { 61 if (model.title != binding.root.context.getString(R.string.system_gpu_driver)) {
61 version.visibility = View.VISIBLE
62 description.visibility = View.VISIBLE
63 buttonDelete.visibility = View.VISIBLE 62 buttonDelete.visibility = View.VISIBLE
64 } else { 63 } else {
65 version.visibility = View.GONE
66 description.visibility = View.GONE
67 buttonDelete.visibility = View.GONE 64 buttonDelete.visibility = View.GONE
68 } 65 }
69 } 66 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 1f591ced1..937b8faf1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -927,7 +927,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
927 emulationThread.join() 927 emulationThread.join()
928 emulationThread = Thread({ 928 emulationThread = Thread({
929 Log.debug("[EmulationFragment] Starting emulation thread.") 929 Log.debug("[EmulationFragment] Starting emulation thread.")
930 NativeLibrary.run(gamePath, programIndex) 930 NativeLibrary.run(gamePath, programIndex, false)
931 }, "NativeEmulation") 931 }, "NativeEmulation")
932 emulationThread.start() 932 emulationThread.start()
933 } 933 }
@@ -981,7 +981,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
981 State.STOPPED -> { 981 State.STOPPED -> {
982 emulationThread = Thread({ 982 emulationThread = Thread({
983 Log.debug("[EmulationFragment] Starting emulation thread.") 983 Log.debug("[EmulationFragment] Starting emulation thread.")
984 NativeLibrary.run(gamePath, programIndex) 984 NativeLibrary.run(gamePath, programIndex, true)
985 }, "NativeEmulation") 985 }, "NativeEmulation")
986 emulationThread.start() 986 emulationThread.start()
987 } 987 }
diff --git a/src/android/app/src/main/jni/applets/software_keyboard.cpp b/src/android/app/src/main/jni/applets/software_keyboard.cpp
index 74e040478..9943483e8 100644
--- a/src/android/app/src/main/jni/applets/software_keyboard.cpp
+++ b/src/android/app/src/main/jni/applets/software_keyboard.cpp
@@ -82,7 +82,7 @@ AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobj
82 const jstring string = reinterpret_cast<jstring>(env->GetObjectField( 82 const jstring string = reinterpret_cast<jstring>(env->GetObjectField(
83 object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;"))); 83 object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;")));
84 return ResultData{GetJString(env, string), 84 return ResultData{GetJString(env, string),
85 static_cast<Service::AM::Applets::SwkbdResult>(env->GetIntField( 85 static_cast<Service::AM::Frontend::SwkbdResult>(env->GetIntField(
86 object, env->GetFieldID(s_keyboard_data_class, "result", "I")))}; 86 object, env->GetFieldID(s_keyboard_data_class, "result", "I")))};
87} 87}
88 88
@@ -149,7 +149,7 @@ void AndroidKeyboard::ShowNormalKeyboard() const {
149} 149}
150 150
151void AndroidKeyboard::ShowTextCheckDialog( 151void AndroidKeyboard::ShowTextCheckDialog(
152 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 152 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
153 std::u16string text_check_message) const { 153 std::u16string text_check_message) const {
154 LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog."); 154 LOG_WARNING(Frontend, "(STUBBED) called, backend requested to show the text check dialog.");
155} 155}
@@ -204,7 +204,7 @@ void AndroidKeyboard::InlineTextChanged(
204 "\ncursor_position={}", 204 "\ncursor_position={}",
205 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); 205 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
206 206
207 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, 207 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
208 text_parameters.input_text, text_parameters.cursor_position); 208 text_parameters.input_text, text_parameters.cursor_position);
209} 209}
210 210
@@ -219,7 +219,7 @@ void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) {
219 219
220 m_current_text += submitted_text; 220 m_current_text += submitted_text;
221 221
222 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text, 222 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
223 m_current_text.size()); 223 m_current_text.size());
224} 224}
225 225
@@ -236,12 +236,12 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
236 case KEYCODE_BACK: 236 case KEYCODE_BACK:
237 case KEYCODE_ENTER: 237 case KEYCODE_ENTER:
238 m_is_inline_active = false; 238 m_is_inline_active = false;
239 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, m_current_text, 239 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter, m_current_text,
240 static_cast<s32>(m_current_text.size())); 240 static_cast<s32>(m_current_text.size()));
241 break; 241 break;
242 case KEYCODE_DEL: 242 case KEYCODE_DEL:
243 m_current_text.pop_back(); 243 m_current_text.pop_back();
244 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, m_current_text, 244 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
245 m_current_text.size()); 245 m_current_text.size());
246 break; 246 break;
247 } 247 }
diff --git a/src/android/app/src/main/jni/applets/software_keyboard.h b/src/android/app/src/main/jni/applets/software_keyboard.h
index b2fb59b68..2affc01f6 100644
--- a/src/android/app/src/main/jni/applets/software_keyboard.h
+++ b/src/android/app/src/main/jni/applets/software_keyboard.h
@@ -24,7 +24,7 @@ public:
24 24
25 void ShowNormalKeyboard() const override; 25 void ShowNormalKeyboard() const override;
26 26
27 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 27 void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
28 std::u16string text_check_message) const override; 28 std::u16string text_check_message) const override;
29 29
30 void ShowInlineKeyboard( 30 void ShowInlineKeyboard(
@@ -45,7 +45,7 @@ private:
45 static ResultData CreateFromFrontend(jobject object); 45 static ResultData CreateFromFrontend(jobject object);
46 46
47 std::string text; 47 std::string text;
48 Service::AM::Applets::SwkbdResult result{}; 48 Service::AM::Frontend::SwkbdResult result{};
49 }; 49 };
50 50
51 void SubmitNormalText(const ResultData& result) const; 51 void SubmitNormalText(const ResultData& result) const;
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 64627db88..654510129 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -42,14 +42,15 @@
42#include "core/frontend/applets/cabinet.h" 42#include "core/frontend/applets/cabinet.h"
43#include "core/frontend/applets/controller.h" 43#include "core/frontend/applets/controller.h"
44#include "core/frontend/applets/error.h" 44#include "core/frontend/applets/error.h"
45#include "core/frontend/applets/general_frontend.h" 45#include "core/frontend/applets/general.h"
46#include "core/frontend/applets/mii_edit.h" 46#include "core/frontend/applets/mii_edit.h"
47#include "core/frontend/applets/profile_select.h" 47#include "core/frontend/applets/profile_select.h"
48#include "core/frontend/applets/software_keyboard.h" 48#include "core/frontend/applets/software_keyboard.h"
49#include "core/frontend/applets/web_browser.h" 49#include "core/frontend/applets/web_browser.h"
50#include "core/hle/service/am/applet_ae.h" 50#include "core/hle/service/am/applet_ae.h"
51#include "core/hle/service/am/applet_manager.h"
51#include "core/hle/service/am/applet_oe.h" 52#include "core/hle/service/am/applet_oe.h"
52#include "core/hle/service/am/applets/applets.h" 53#include "core/hle/service/am/frontend/applets.h"
53#include "core/hle/service/filesystem/filesystem.h" 54#include "core/hle/service/filesystem/filesystem.h"
54#include "core/loader/loader.h" 55#include "core/loader/loader.h"
55#include "frontend_common/config.h" 56#include "frontend_common/config.h"
@@ -211,8 +212,15 @@ void EmulationSession::InitializeSystem(bool reload) {
211 m_system.GetFileSystemController().CreateFactories(*m_vfs); 212 m_system.GetFileSystemController().CreateFactories(*m_vfs);
212} 213}
213 214
215void EmulationSession::SetAppletId(int applet_id) {
216 m_applet_id = applet_id;
217 m_system.GetFrontendAppletHolder().SetCurrentAppletId(
218 static_cast<Service::AM::AppletId>(m_applet_id));
219}
220
214Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath, 221Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string& filepath,
215 const std::size_t program_index) { 222 const std::size_t program_index,
223 const bool frontend_initiated) {
216 std::scoped_lock lock(m_mutex); 224 std::scoped_lock lock(m_mutex);
217 225
218 // Create the render window. 226 // Create the render window.
@@ -226,7 +234,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
226 m_system.ApplySettings(); 234 m_system.ApplySettings();
227 Settings::LogSettings(); 235 Settings::LogSettings();
228 m_system.HIDCore().ReloadInputDevices(); 236 m_system.HIDCore().ReloadInputDevices();
229 m_system.SetAppletFrontendSet({ 237 m_system.SetFrontendAppletSet({
230 nullptr, // Amiibo Settings 238 nullptr, // Amiibo Settings
231 nullptr, // Controller Selector 239 nullptr, // Controller Selector
232 nullptr, // Error Display 240 nullptr, // Error Display
@@ -242,8 +250,13 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
242 ConfigureFilesystemProvider(filepath); 250 ConfigureFilesystemProvider(filepath);
243 251
244 // Load the ROM. 252 // Load the ROM.
245 m_load_result = 253 Service::AM::FrontendAppletParameters params{
246 m_system.Load(EmulationSession::GetInstance().Window(), filepath, 0, program_index); 254 .applet_id = static_cast<Service::AM::AppletId>(m_applet_id),
255 .launch_type = frontend_initiated ? Service::AM::LaunchType::FrontendInitiated
256 : Service::AM::LaunchType::ApplicationInitiated,
257 .program_index = static_cast<s32>(program_index),
258 };
259 m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath, params);
247 if (m_load_result != Core::SystemResultStatus::Success) { 260 if (m_load_result != Core::SystemResultStatus::Success) {
248 return m_load_result; 261 return m_load_result;
249 } 262 }
@@ -339,6 +352,9 @@ void EmulationSession::RunEmulation() {
339 } 352 }
340 } 353 }
341 } 354 }
355
356 // Reset current applet ID.
357 m_applet_id = static_cast<int>(Service::AM::AppletId::Application);
342} 358}
343 359
344bool EmulationSession::IsHandheldOnly() { 360bool EmulationSession::IsHandheldOnly() {
@@ -434,7 +450,8 @@ u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
434} 450}
435 451
436static Core::SystemResultStatus RunEmulation(const std::string& filepath, 452static Core::SystemResultStatus RunEmulation(const std::string& filepath,
437 const size_t program_index = 0) { 453 const size_t program_index,
454 const bool frontend_initiated) {
438 MicroProfileOnThreadCreate("EmuThread"); 455 MicroProfileOnThreadCreate("EmuThread");
439 SCOPE_EXIT({ MicroProfileShutdown(); }); 456 SCOPE_EXIT({ MicroProfileShutdown(); });
440 457
@@ -447,7 +464,8 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath,
447 464
448 SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); }); 465 SCOPE_EXIT({ EmulationSession::GetInstance().ShutdownEmulation(); });
449 466
450 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index); 467 jconst result = EmulationSession::GetInstance().InitializeEmulation(filepath, program_index,
468 frontend_initiated);
451 if (result != Core::SystemResultStatus::Success) { 469 if (result != Core::SystemResultStatus::Success) {
452 return result; 470 return result;
453 } 471 }
@@ -744,10 +762,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj
744} 762}
745 763
746void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path, 764void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
747 jint j_program_index) { 765 jint j_program_index,
766 jboolean j_frontend_initiated) {
748 const std::string path = GetJString(env, j_path); 767 const std::string path = GetJString(env, j_path);
749 768
750 const Core::SystemResultStatus result{RunEmulation(path, j_program_index)}; 769 const Core::SystemResultStatus result{
770 RunEmulation(path, j_program_index, j_frontend_initiated)};
751 if (result != Core::SystemResultStatus::Success) { 771 if (result != Core::SystemResultStatus::Success) {
752 env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), 772 env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
753 IDCache::GetExitEmulationActivity(), static_cast<int>(result)); 773 IDCache::GetExitEmulationActivity(), static_cast<int>(result));
@@ -809,13 +829,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j
809 829
810void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz, 830void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz,
811 jint jappletId) { 831 jint jappletId) {
812 EmulationSession::GetInstance().System().GetAppletManager().SetCurrentAppletId( 832 EmulationSession::GetInstance().SetAppletId(jappletId);
813 static_cast<Service::AM::Applets::AppletId>(jappletId));
814} 833}
815 834
816void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz, 835void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass clazz,
817 jint jcabinetMode) { 836 jint jcabinetMode) {
818 EmulationSession::GetInstance().System().GetAppletManager().SetCabinetMode( 837 EmulationSession::GetInstance().System().GetFrontendAppletHolder().SetCabinetMode(
819 static_cast<Service::NFP::CabinetMode>(jcabinetMode)); 838 static_cast<Service::NFP::CabinetMode>(jcabinetMode));
820} 839}
821 840
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h
index bfe3fccca..e49d4e015 100644
--- a/src/android/app/src/main/jni/native.h
+++ b/src/android/app/src/main/jni/native.h
@@ -45,8 +45,10 @@ public:
45 const Core::PerfStatsResults& PerfStats(); 45 const Core::PerfStatsResults& PerfStats();
46 void ConfigureFilesystemProvider(const std::string& filepath); 46 void ConfigureFilesystemProvider(const std::string& filepath);
47 void InitializeSystem(bool reload); 47 void InitializeSystem(bool reload);
48 void SetAppletId(int applet_id);
48 Core::SystemResultStatus InitializeEmulation(const std::string& filepath, 49 Core::SystemResultStatus InitializeEmulation(const std::string& filepath,
49 const std::size_t program_index = 0); 50 const std::size_t program_index,
51 const bool frontend_initiated);
50 52
51 bool IsHandheldOnly(); 53 bool IsHandheldOnly();
52 void SetDeviceType([[maybe_unused]] int index, int type); 54 void SetDeviceType([[maybe_unused]] int index, int type);
@@ -79,6 +81,7 @@ private:
79 std::atomic<bool> m_is_paused = false; 81 std::atomic<bool> m_is_paused = false;
80 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; 82 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
81 std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; 83 std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
84 int m_applet_id{1};
82 85
83 // GPU driver parameters 86 // GPU driver parameters
84 std::shared_ptr<Common::DynamicLibrary> m_vulkan_library; 87 std::shared_ptr<Common::DynamicLibrary> m_vulkan_library;
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index e982d03be..4e4ed1789 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -210,8 +210,6 @@ add_library(audio_core STATIC
210 sink/sink_stream.h 210 sink/sink_stream.h
211) 211)
212 212
213create_target_directory_groups(audio_core)
214
215if (MSVC) 213if (MSVC)
216 target_compile_options(audio_core PRIVATE 214 target_compile_options(audio_core PRIVATE
217 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data 215 /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data
@@ -267,3 +265,5 @@ endif()
267if (YUZU_USE_PRECOMPILED_HEADERS) 265if (YUZU_USE_PRECOMPILED_HEADERS)
268 target_precompile_headers(audio_core PRIVATE precompiled_headers.h) 266 target_precompile_headers(audio_core PRIVATE precompiled_headers.h)
269endif() 267endif()
268
269create_target_directory_groups(audio_core)
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 8c57d47c6..85926fc8f 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -106,6 +106,7 @@ add_library(common STATIC
106 precompiled_headers.h 106 precompiled_headers.h
107 quaternion.h 107 quaternion.h
108 range_map.h 108 range_map.h
109 range_mutex.h
109 reader_writer_queue.h 110 reader_writer_queue.h
110 ring_buffer.h 111 ring_buffer.h
111 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp 112 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
@@ -244,8 +245,6 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
244 ) 245 )
245endif() 246endif()
246 247
247create_target_directory_groups(common)
248
249target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile stb::headers Threads::Threads) 248target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile stb::headers Threads::Threads)
250target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle) 249target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle)
251 250
@@ -257,3 +256,5 @@ endif()
257if (YUZU_USE_PRECOMPILED_HEADERS) 256if (YUZU_USE_PRECOMPILED_HEADERS)
258 target_precompile_headers(common PRIVATE precompiled_headers.h) 257 target_precompile_headers(common PRIVATE precompiled_headers.h)
259endif() 258endif()
259
260create_target_directory_groups(common)
diff --git a/src/common/range_mutex.h b/src/common/range_mutex.h
new file mode 100644
index 000000000..d6c949811
--- /dev/null
+++ b/src/common/range_mutex.h
@@ -0,0 +1,93 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <condition_variable>
7#include <mutex>
8
9#include "common/intrusive_list.h"
10
11namespace Common {
12
13class ScopedRangeLock;
14
15class RangeMutex {
16public:
17 explicit RangeMutex() = default;
18 ~RangeMutex() = default;
19
20private:
21 friend class ScopedRangeLock;
22
23 void Lock(ScopedRangeLock& l);
24 void Unlock(ScopedRangeLock& l);
25 bool HasIntersectionLocked(ScopedRangeLock& l);
26
27private:
28 std::mutex m_mutex;
29 std::condition_variable m_cv;
30
31 using LockList = Common::IntrusiveListBaseTraits<ScopedRangeLock>::ListType;
32 LockList m_list;
33};
34
35class ScopedRangeLock : public Common::IntrusiveListBaseNode<ScopedRangeLock> {
36public:
37 explicit ScopedRangeLock(RangeMutex& mutex, u64 address, u64 size)
38 : m_mutex(mutex), m_address(address), m_size(size) {
39 if (m_size > 0) {
40 m_mutex.Lock(*this);
41 }
42 }
43 ~ScopedRangeLock() {
44 if (m_size > 0) {
45 m_mutex.Unlock(*this);
46 }
47 }
48
49 u64 GetAddress() const {
50 return m_address;
51 }
52
53 u64 GetSize() const {
54 return m_size;
55 }
56
57private:
58 RangeMutex& m_mutex;
59 const u64 m_address{};
60 const u64 m_size{};
61};
62
63inline void RangeMutex::Lock(ScopedRangeLock& l) {
64 std::unique_lock lk{m_mutex};
65 m_cv.wait(lk, [&] { return !HasIntersectionLocked(l); });
66 m_list.push_back(l);
67}
68
69inline void RangeMutex::Unlock(ScopedRangeLock& l) {
70 {
71 std::scoped_lock lk{m_mutex};
72 m_list.erase(m_list.iterator_to(l));
73 }
74 m_cv.notify_all();
75}
76
77inline bool RangeMutex::HasIntersectionLocked(ScopedRangeLock& l) {
78 const auto cur_begin = l.GetAddress();
79 const auto cur_last = l.GetAddress() + l.GetSize() - 1;
80
81 for (const auto& other : m_list) {
82 const auto other_begin = other.GetAddress();
83 const auto other_last = other.GetAddress() + other.GetSize() - 1;
84
85 if (cur_begin <= other_last && other_begin <= cur_last) {
86 return true;
87 }
88 }
89
90 return false;
91}
92
93} // namespace Common
diff --git a/src/common/settings.h b/src/common/settings.h
index 16749ab68..f1b1add56 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -134,12 +134,12 @@ struct Values {
134 Linkage linkage{}; 134 Linkage linkage{};
135 135
136 // Audio 136 // Audio
137 Setting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine", Category::Audio, 137 SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",
138 Specialization::RuntimeList}; 138 Category::Audio, Specialization::RuntimeList};
139 Setting<std::string> audio_output_device_id{linkage, "auto", "output_device", Category::Audio, 139 SwitchableSetting<std::string> audio_output_device_id{
140 Specialization::RuntimeList}; 140 linkage, "auto", "output_device", Category::Audio, Specialization::RuntimeList};
141 Setting<std::string> audio_input_device_id{linkage, "auto", "input_device", Category::Audio, 141 SwitchableSetting<std::string> audio_input_device_id{
142 Specialization::RuntimeList}; 142 linkage, "auto", "input_device", Category::Audio, Specialization::RuntimeList};
143 SwitchableSetting<AudioMode, true> sound_index{ 143 SwitchableSetting<AudioMode, true> sound_index{
144 linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround, 144 linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround,
145 "sound_index", Category::SystemAudio, Specialization::Default, true, 145 "sound_index", Category::SystemAudio, Specialization::Default, true,
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 347bbf2d0..570acb193 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -176,8 +176,8 @@ add_library(core STATIC
176 frontend/applets/controller.h 176 frontend/applets/controller.h
177 frontend/applets/error.cpp 177 frontend/applets/error.cpp
178 frontend/applets/error.h 178 frontend/applets/error.h
179 frontend/applets/general_frontend.cpp 179 frontend/applets/general.cpp
180 frontend/applets/general_frontend.h 180 frontend/applets/general.h
181 frontend/applets/mii_edit.cpp 181 frontend/applets/mii_edit.cpp
182 frontend/applets/mii_edit.h 182 frontend/applets/mii_edit.h
183 frontend/applets/profile_select.cpp 183 frontend/applets/profile_select.cpp
@@ -390,39 +390,101 @@ add_library(core STATIC
390 hle/service/acc/errors.h 390 hle/service/acc/errors.h
391 hle/service/acc/profile_manager.cpp 391 hle/service/acc/profile_manager.cpp
392 hle/service/acc/profile_manager.h 392 hle/service/acc/profile_manager.h
393 hle/service/am/frontend/applet_cabinet.cpp
394 hle/service/am/frontend/applet_cabinet.h
395 hle/service/am/frontend/applet_controller.cpp
396 hle/service/am/frontend/applet_controller.h
397 hle/service/am/frontend/applet_error.cpp
398 hle/service/am/frontend/applet_error.h
399 hle/service/am/frontend/applet_general.cpp
400 hle/service/am/frontend/applet_general.h
401 hle/service/am/frontend/applet_mii_edit.cpp
402 hle/service/am/frontend/applet_mii_edit.h
403 hle/service/am/frontend/applet_mii_edit_types.h
404 hle/service/am/frontend/applet_profile_select.cpp
405 hle/service/am/frontend/applet_profile_select.h
406 hle/service/am/frontend/applet_software_keyboard.cpp
407 hle/service/am/frontend/applet_software_keyboard.h
408 hle/service/am/frontend/applet_software_keyboard_types.h
409 hle/service/am/frontend/applet_web_browser.cpp
410 hle/service/am/frontend/applet_web_browser.h
411 hle/service/am/frontend/applet_web_browser_types.h
412 hle/service/am/frontend/applets.cpp
413 hle/service/am/frontend/applets.h
393 hle/service/am/am.cpp 414 hle/service/am/am.cpp
394 hle/service/am/am.h 415 hle/service/am/am.h
416 hle/service/am/am_results.h
417 hle/service/am/am_types.h
418 hle/service/am/applet.cpp
419 hle/service/am/applet.h
395 hle/service/am/applet_ae.cpp 420 hle/service/am/applet_ae.cpp
396 hle/service/am/applet_ae.h 421 hle/service/am/applet_ae.h
422 hle/service/am/applet_manager.cpp
423 hle/service/am/applet_data_broker.cpp
424 hle/service/am/applet_data_broker.h
425 hle/service/am/applet_manager.h
397 hle/service/am/applet_oe.cpp 426 hle/service/am/applet_oe.cpp
398 hle/service/am/applet_oe.h 427 hle/service/am/applet_oe.h
399 hle/service/am/applets/applet_cabinet.cpp 428 hle/service/am/applet_common_functions.cpp
400 hle/service/am/applets/applet_cabinet.h 429 hle/service/am/applet_common_functions.h
401 hle/service/am/applets/applet_controller.cpp 430 hle/service/am/applet_message_queue.cpp
402 hle/service/am/applets/applet_controller.h 431 hle/service/am/applet_message_queue.h
403 hle/service/am/applets/applet_error.cpp 432 hle/service/am/application_creator.cpp
404 hle/service/am/applets/applet_error.h 433 hle/service/am/application_creator.h
405 hle/service/am/applets/applet_general_backend.cpp 434 hle/service/am/application_functions.cpp
406 hle/service/am/applets/applet_general_backend.h 435 hle/service/am/application_functions.h
407 hle/service/am/applets/applet_mii_edit.cpp 436 hle/service/am/application_proxy.cpp
408 hle/service/am/applets/applet_mii_edit.h 437 hle/service/am/application_proxy.h
409 hle/service/am/applets/applet_mii_edit_types.h 438 hle/service/am/audio_controller.cpp
410 hle/service/am/applets/applet_profile_select.cpp 439 hle/service/am/audio_controller.h
411 hle/service/am/applets/applet_profile_select.h 440 hle/service/am/common_state_getter.cpp
412 hle/service/am/applets/applet_software_keyboard.cpp 441 hle/service/am/common_state_getter.h
413 hle/service/am/applets/applet_software_keyboard.h 442 hle/service/am/debug_functions.cpp
414 hle/service/am/applets/applet_software_keyboard_types.h 443 hle/service/am/debug_functions.h
415 hle/service/am/applets/applet_web_browser.cpp 444 hle/service/am/display_controller.cpp
416 hle/service/am/applets/applet_web_browser.h 445 hle/service/am/display_controller.h
417 hle/service/am/applets/applet_web_browser_types.h 446 hle/service/am/global_state_controller.cpp
418 hle/service/am/applets/applets.cpp 447 hle/service/am/global_state_controller.h
419 hle/service/am/applets/applets.h 448 hle/service/am/hid_registration.cpp
449 hle/service/am/hid_registration.h
450 hle/service/am/home_menu_functions.cpp
451 hle/service/am/home_menu_functions.h
420 hle/service/am/idle.cpp 452 hle/service/am/idle.cpp
421 hle/service/am/idle.h 453 hle/service/am/idle.h
454 hle/service/am/library_applet_accessor.cpp
455 hle/service/am/library_applet_accessor.h
456 hle/service/am/library_applet_creator.cpp
457 hle/service/am/library_applet_creator.h
458 hle/service/am/library_applet_proxy.cpp
459 hle/service/am/library_applet_proxy.h
460 hle/service/am/library_applet_self_accessor.cpp
461 hle/service/am/library_applet_self_accessor.h
462 hle/service/am/library_applet_storage.cpp
463 hle/service/am/library_applet_storage.h
464 hle/service/am/lock_accessor.cpp
465 hle/service/am/lock_accessor.h
466 hle/service/am/managed_layer_holder.cpp
467 hle/service/am/managed_layer_holder.h
422 hle/service/am/omm.cpp 468 hle/service/am/omm.cpp
423 hle/service/am/omm.h 469 hle/service/am/omm.h
470 hle/service/am/process_winding_controller.cpp
471 hle/service/am/process_winding_controller.h
472 hle/service/am/process.cpp
473 hle/service/am/process.h
474 hle/service/am/self_controller.cpp
475 hle/service/am/self_controller.h
476 hle/service/am/system_applet_proxy.cpp
477 hle/service/am/system_applet_proxy.h
478 hle/service/am/system_buffer_manager.cpp
479 hle/service/am/system_buffer_manager.h
424 hle/service/am/spsm.cpp 480 hle/service/am/spsm.cpp
425 hle/service/am/spsm.h 481 hle/service/am/spsm.h
482 hle/service/am/storage_accessor.cpp
483 hle/service/am/storage_accessor.h
484 hle/service/am/storage.cpp
485 hle/service/am/storage.h
486 hle/service/am/window_controller.cpp
487 hle/service/am/window_controller.h
426 hle/service/aoc/aoc_u.cpp 488 hle/service/aoc/aoc_u.cpp
427 hle/service/aoc/aoc_u.h 489 hle/service/aoc/aoc_u.h
428 hle/service/apm/apm.cpp 490 hle/service/apm/apm.cpp
@@ -486,6 +548,8 @@ add_library(core STATIC
486 hle/service/es/es.h 548 hle/service/es/es.h
487 hle/service/eupld/eupld.cpp 549 hle/service/eupld/eupld.cpp
488 hle/service/eupld/eupld.h 550 hle/service/eupld/eupld.h
551 hle/service/event.cpp
552 hle/service/event.h
489 hle/service/fatal/fatal.cpp 553 hle/service/fatal/fatal.cpp
490 hle/service/fatal/fatal.h 554 hle/service/fatal/fatal.h
491 hle/service/fatal/fatal_p.cpp 555 hle/service/fatal/fatal_p.cpp
@@ -915,8 +979,6 @@ else()
915 ) 979 )
916endif() 980endif()
917 981
918create_target_directory_groups(core)
919
920target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz) 982target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
921target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API) 983target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls RenderDoc::API)
922if (MINGW) 984if (MINGW)
@@ -994,3 +1056,5 @@ endif()
994if (YUZU_ENABLE_LTO) 1056if (YUZU_ENABLE_LTO)
995 set_property(TARGET core PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) 1057 set_property(TARGET core PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
996endif() 1058endif()
1059
1060create_target_directory_groups(core)
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 1b412ac98..435ef6793 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -36,7 +36,8 @@
36#include "core/hle/kernel/kernel.h" 36#include "core/hle/kernel/kernel.h"
37#include "core/hle/kernel/physical_core.h" 37#include "core/hle/kernel/physical_core.h"
38#include "core/hle/service/acc/profile_manager.h" 38#include "core/hle/service/acc/profile_manager.h"
39#include "core/hle/service/am/applets/applets.h" 39#include "core/hle/service/am/applet_manager.h"
40#include "core/hle/service/am/frontend/applets.h"
40#include "core/hle/service/apm/apm_controller.h" 41#include "core/hle/service/apm/apm_controller.h"
41#include "core/hle/service/filesystem/filesystem.h" 42#include "core/hle/service/filesystem/filesystem.h"
42#include "core/hle/service/glue/glue_manager.h" 43#include "core/hle/service/glue/glue_manager.h"
@@ -135,8 +136,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
135 136
136struct System::Impl { 137struct System::Impl {
137 explicit Impl(System& system) 138 explicit Impl(System& system)
138 : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, 139 : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
139 cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{} {} 140 reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {}
140 141
141 void Initialize(System& system) { 142 void Initialize(System& system) {
142 device_memory = std::make_unique<Core::DeviceMemory>(); 143 device_memory = std::make_unique<Core::DeviceMemory>();
@@ -157,7 +158,7 @@ struct System::Impl {
157 } 158 }
158 159
159 // Create default implementations of applets if one is not provided. 160 // Create default implementations of applets if one is not provided.
160 applet_manager.SetDefaultAppletsIfMissing(); 161 frontend_applets.SetDefaultAppletsIfMissing();
161 162
162 is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); 163 is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
163 164
@@ -200,22 +201,22 @@ struct System::Impl {
200 system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:s", true); 201 system.ServiceManager().GetService<Service::PSC::Time::StaticService>("time:s", true);
201 202
202 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock; 203 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock;
203 static_service_a->GetStandardUserSystemClock(user_clock); 204 static_service_a->GetStandardUserSystemClock(&user_clock);
204 205
205 std::shared_ptr<Service::PSC::Time::SystemClock> local_clock; 206 std::shared_ptr<Service::PSC::Time::SystemClock> local_clock;
206 static_service_a->GetStandardLocalSystemClock(local_clock); 207 static_service_a->GetStandardLocalSystemClock(&local_clock);
207 208
208 std::shared_ptr<Service::PSC::Time::SystemClock> network_clock; 209 std::shared_ptr<Service::PSC::Time::SystemClock> network_clock;
209 static_service_s->GetStandardNetworkSystemClock(network_clock); 210 static_service_s->GetStandardNetworkSystemClock(&network_clock);
210 211
211 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service; 212 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service;
212 static_service_a->GetTimeZoneService(timezone_service); 213 static_service_a->GetTimeZoneService(&timezone_service);
213 214
214 Service::PSC::Time::LocationName name{}; 215 Service::PSC::Time::LocationName name{};
215 auto new_name = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); 216 auto new_name = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
216 std::memcpy(name.name.data(), new_name.data(), std::min(name.name.size(), new_name.size())); 217 std::memcpy(name.data(), new_name.data(), std::min(name.size(), new_name.size()));
217 218
218 timezone_service->SetDeviceLocation(name); 219 timezone_service->SetDeviceLocationName(name);
219 220
220 u64 time_offset = 0; 221 u64 time_offset = 0;
221 if (Settings::values.custom_rtc_enabled) { 222 if (Settings::values.custom_rtc_enabled) {
@@ -233,7 +234,7 @@ struct System::Impl {
233 234
234 local_clock->SetCurrentTime(new_time); 235 local_clock->SetCurrentTime(new_time);
235 236
236 network_clock->GetSystemClockContext(context); 237 network_clock->GetSystemClockContext(&context);
237 settings_service->SetNetworkSystemClockContext(context); 238 settings_service->SetNetworkSystemClockContext(context);
238 network_clock->SetCurrentTime(new_time); 239 network_clock->SetCurrentTime(new_time);
239 } 240 }
@@ -330,16 +331,27 @@ struct System::Impl {
330 } 331 }
331 332
332 SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window, 333 SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
333 const std::string& filepath, u64 program_id, 334 const std::string& filepath,
334 std::size_t program_index) { 335 Service::AM::FrontendAppletParameters& params) {
335 app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath), 336 app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
336 program_id, program_index); 337 params.program_id, params.program_index);
337 338
338 if (!app_loader) { 339 if (!app_loader) {
339 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); 340 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
340 return SystemResultStatus::ErrorGetLoader; 341 return SystemResultStatus::ErrorGetLoader;
341 } 342 }
342 343
344 if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
345 LOG_ERROR(Core, "Failed to find title id for ROM!");
346 }
347
348 std::string name = "Unknown program";
349 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
350 LOG_ERROR(Core, "Failed to read title for ROM!");
351 }
352
353 LOG_INFO(Core, "Loading {} ({})", name, params.program_id);
354
343 InitializeKernel(system); 355 InitializeKernel(system);
344 356
345 // Create the application process. 357 // Create the application process.
@@ -373,9 +385,14 @@ struct System::Impl {
373 cheat_engine->Initialize(); 385 cheat_engine->Initialize();
374 } 386 }
375 387
388 // Register with applet manager.
389 applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(),
390 params);
391
376 // All threads are started, begin main process execution, now that we're in the clear. 392 // All threads are started, begin main process execution, now that we're in the clear.
377 main_process->Run(load_parameters->main_thread_priority, 393 main_process->Run(load_parameters->main_thread_priority,
378 load_parameters->main_thread_stack_size); 394 load_parameters->main_thread_stack_size);
395 main_process->Close();
379 396
380 if (Settings::values.gamecard_inserted) { 397 if (Settings::values.gamecard_inserted) {
381 if (Settings::values.gamecard_current_game) { 398 if (Settings::values.gamecard_current_game) {
@@ -386,21 +403,13 @@ struct System::Impl {
386 } 403 }
387 } 404 }
388 405
389 if (app_loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) { 406 perf_stats = std::make_unique<PerfStats>(params.program_id);
390 LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result);
391 }
392 perf_stats = std::make_unique<PerfStats>(program_id);
393 // Reset counters and set time origin to current frame 407 // Reset counters and set time origin to current frame
394 GetAndResetPerfStats(); 408 GetAndResetPerfStats();
395 perf_stats->BeginSystemFrame(); 409 perf_stats->BeginSystemFrame();
396 410
397 std::string name = "Unknown Game";
398 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
399 LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);
400 }
401
402 std::string title_version; 411 std::string title_version;
403 const FileSys::PatchManager pm(program_id, system.GetFileSystemController(), 412 const FileSys::PatchManager pm(params.program_id, system.GetFileSystemController(),
404 system.GetContentProvider()); 413 system.GetContentProvider());
405 const auto metadata = pm.GetControlMetadata(); 414 const auto metadata = pm.GetControlMetadata();
406 if (metadata.first != nullptr) { 415 if (metadata.first != nullptr) {
@@ -409,14 +418,15 @@ struct System::Impl {
409 if (auto room_member = room_network.GetRoomMember().lock()) { 418 if (auto room_member = room_network.GetRoomMember().lock()) {
410 Network::GameInfo game_info; 419 Network::GameInfo game_info;
411 game_info.name = name; 420 game_info.name = name;
412 game_info.id = program_id; 421 game_info.id = params.program_id;
413 game_info.version = title_version; 422 game_info.version = title_version;
414 room_member->SendGameInfo(game_info); 423 room_member->SendGameInfo(game_info);
415 } 424 }
416 425
417 // Workarounds: 426 // Workarounds:
418 // Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK 427 // Activate this in Super Smash Brothers Ultimate, it only affects AMD cards using AMDVLK
419 Settings::values.renderer_amdvlk_depth_bias_workaround = program_id == 0x1006A800016E000ULL; 428 Settings::values.renderer_amdvlk_depth_bias_workaround =
429 params.program_id == 0x1006A800016E000ULL;
420 430
421 status = SystemResultStatus::Success; 431 status = SystemResultStatus::Success;
422 return status; 432 return status;
@@ -455,6 +465,7 @@ struct System::Impl {
455 } 465 }
456 kernel.CloseServices(); 466 kernel.CloseServices();
457 kernel.ShutdownCores(); 467 kernel.ShutdownCores();
468 applet_manager.Reset();
458 services.reset(); 469 services.reset();
459 service_manager.reset(); 470 service_manager.reset();
460 fs_controller.Reset(); 471 fs_controller.Reset();
@@ -566,8 +577,9 @@ struct System::Impl {
566 577
567 std::unique_ptr<Tools::RenderdocAPI> renderdoc_api; 578 std::unique_ptr<Tools::RenderdocAPI> renderdoc_api;
568 579
569 /// Frontend applets 580 /// Applets
570 Service::AM::Applets::AppletManager applet_manager; 581 Service::AM::AppletManager applet_manager;
582 Service::AM::Frontend::FrontendAppletHolder frontend_applets;
571 583
572 /// APM (Performance) services 584 /// APM (Performance) services
573 Service::APM::Controller apm_controller{core_timing}; 585 Service::APM::Controller apm_controller{core_timing};
@@ -680,8 +692,8 @@ void System::InitializeDebugger() {
680} 692}
681 693
682SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath, 694SystemResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
683 u64 program_id, std::size_t program_index) { 695 Service::AM::FrontendAppletParameters& params) {
684 return impl->Load(*this, emu_window, filepath, program_id, program_index); 696 return impl->Load(*this, emu_window, filepath, params);
685} 697}
686 698
687bool System::IsPoweredOn() const { 699bool System::IsPoweredOn() const {
@@ -871,19 +883,19 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
871 impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size); 883 impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
872} 884}
873 885
874void System::SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set) { 886void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
875 impl->applet_manager.SetAppletFrontendSet(std::move(set)); 887 impl->frontend_applets.SetFrontendAppletSet(std::move(set));
876} 888}
877 889
878void System::SetDefaultAppletFrontendSet() { 890Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() {
879 impl->applet_manager.SetDefaultAppletFrontendSet(); 891 return impl->frontend_applets;
880} 892}
881 893
882Service::AM::Applets::AppletManager& System::GetAppletManager() { 894const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const {
883 return impl->applet_manager; 895 return impl->frontend_applets;
884} 896}
885 897
886const Service::AM::Applets::AppletManager& System::GetAppletManager() const { 898Service::AM::AppletManager& System::GetAppletManager() {
887 return impl->applet_manager; 899 return impl->applet_manager;
888} 900}
889 901
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 {
50class ProfileManager; 50class ProfileManager;
51} // namespace Account 51} // namespace Account
52 52
53namespace AM::Applets { 53namespace AM {
54struct AppletFrontendSet; 54struct FrontendAppletParameters;
55class AppletManager; 55class AppletManager;
56} // namespace AM::Applets 56} // namespace AM
57
58namespace AM::Frontend {
59struct FrontendAppletSet;
60class FrontendAppletHolder;
61} // namespace AM::Frontend
57 62
58namespace APM { 63namespace APM {
59class Controller; 64class Controller;
@@ -203,8 +208,8 @@ public:
203 * @returns SystemResultStatus code, indicating if the operation succeeded. 208 * @returns SystemResultStatus code, indicating if the operation succeeded.
204 */ 209 */
205 [[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window, 210 [[nodiscard]] SystemResultStatus Load(Frontend::EmuWindow& emu_window,
206 const std::string& filepath, u64 program_id = 0, 211 const std::string& filepath,
207 std::size_t program_index = 0); 212 Service::AM::FrontendAppletParameters& params);
208 213
209 /** 214 /**
210 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an 215 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
@@ -344,11 +349,13 @@ public:
344 const std::array<u8, 0x20>& build_id, u64 main_region_begin, 349 const std::array<u8, 0x20>& build_id, u64 main_region_begin,
345 u64 main_region_size); 350 u64 main_region_size);
346 351
347 void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set); 352 void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set);
348 void SetDefaultAppletFrontendSet(); 353
354 [[nodiscard]] Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder();
355 [[nodiscard]] const Service::AM::Frontend::FrontendAppletHolder& GetFrontendAppletHolder()
356 const;
349 357
350 [[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager(); 358 [[nodiscard]] Service::AM::AppletManager& GetAppletManager();
351 [[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
352 359
353 void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider); 360 void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
354 361
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 @@
5 5
6#include <array> 6#include <array>
7#include <atomic> 7#include <atomic>
8#include <bit>
8#include <deque> 9#include <deque>
9#include <memory> 10#include <memory>
10#include <mutex> 11#include <mutex>
11 12
12#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/range_mutex.h"
13#include "common/scratch_buffer.h" 15#include "common/scratch_buffer.h"
14#include "common/virtual_buffer.h" 16#include "common/virtual_buffer.h"
15 17
@@ -180,31 +182,35 @@ private:
180 } 182 }
181 183
182 Common::VirtualBuffer<VAddr> cpu_backing_address; 184 Common::VirtualBuffer<VAddr> cpu_backing_address;
183 static constexpr size_t subentries = 8 / sizeof(u8); 185 using CounterType = u8;
186 using CounterAtomicType = std::atomic_uint8_t;
187 static constexpr size_t subentries = 8 / sizeof(CounterType);
184 static constexpr size_t subentries_mask = subentries - 1; 188 static constexpr size_t subentries_mask = subentries - 1;
189 static constexpr size_t subentries_shift =
190 std::countr_zero(sizeof(u64)) - std::countr_zero(sizeof(CounterType));
185 class CounterEntry final { 191 class CounterEntry final {
186 public: 192 public:
187 CounterEntry() = default; 193 CounterEntry() = default;
188 194
189 std::atomic_uint8_t& Count(std::size_t page) { 195 CounterAtomicType& Count(std::size_t page) {
190 return values[page & subentries_mask]; 196 return values[page & subentries_mask];
191 } 197 }
192 198
193 const std::atomic_uint8_t& Count(std::size_t page) const { 199 const CounterAtomicType& Count(std::size_t page) const {
194 return values[page & subentries_mask]; 200 return values[page & subentries_mask];
195 } 201 }
196 202
197 private: 203 private:
198 std::array<std::atomic_uint8_t, subentries> values{}; 204 std::array<CounterAtomicType, subentries> values{};
199 }; 205 };
200 static_assert(sizeof(CounterEntry) == subentries * sizeof(u8), 206 static_assert(sizeof(CounterEntry) == subentries * sizeof(CounterType),
201 "CounterEntry should be 8 bytes!"); 207 "CounterEntry should be 8 bytes!");
202 208
203 static constexpr size_t num_counter_entries = 209 static constexpr size_t num_counter_entries =
204 (1ULL << (device_virtual_bits - page_bits)) / subentries; 210 (1ULL << (device_virtual_bits - page_bits)) / subentries;
205 using CachedPages = std::array<CounterEntry, num_counter_entries>; 211 using CachedPages = std::array<CounterEntry, num_counter_entries>;
206 std::unique_ptr<CachedPages> cached_pages; 212 std::unique_ptr<CachedPages> cached_pages;
207 std::mutex counter_guard; 213 Common::RangeMutex counter_guard;
208 std::mutex mapping_guard; 214 std::mutex mapping_guard;
209}; 215};
210 216
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) {
213} 213}
214 214
215template <typename Traits> 215template <typename Traits>
216void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, 216void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, Asid asid,
217 Asid asid, bool track) { 217 bool track) {
218 Core::Memory::Memory* process_memory = registered_processes[asid.id]; 218 Core::Memory::Memory* process_memory = registered_processes[asid.id];
219 size_t start_page_d = address >> Memory::YUZU_PAGEBITS; 219 size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
220 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; 220 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
@@ -508,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) {
508 508
509template <typename Traits> 509template <typename Traits>
510void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { 510void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
511 std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); 511 Common::ScopedRangeLock lk(counter_guard, addr, size);
512 const auto Lock = [&] {
513 if (!lk) {
514 lk.lock();
515 }
516 };
517 u64 uncache_begin = 0; 512 u64 uncache_begin = 0;
518 u64 cache_begin = 0; 513 u64 cache_begin = 0;
519 u64 uncache_bytes = 0; 514 u64 uncache_bytes = 0;
@@ -524,22 +519,36 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
524 const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); 519 const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
525 size_t page = addr >> Memory::YUZU_PAGEBITS; 520 size_t page = addr >> Memory::YUZU_PAGEBITS;
526 auto [asid, base_vaddress] = ExtractCPUBacking(page); 521 auto [asid, base_vaddress] = ExtractCPUBacking(page);
527 size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS;
528 auto* memory_device_inter = registered_processes[asid.id]; 522 auto* memory_device_inter = registered_processes[asid.id];
523 const auto release_pending = [&] {
524 if (uncache_bytes > 0) {
525 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
526 uncache_bytes, false);
527 uncache_bytes = 0;
528 }
529 if (cache_bytes > 0) {
530 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
531 cache_bytes, true);
532 cache_bytes = 0;
533 }
534 };
529 for (; page != page_end; ++page) { 535 for (; page != page_end; ++page) {
530 std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page); 536 CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page);
537 auto [asid_2, vpage] = ExtractCPUBacking(page);
538 vpage >>= Memory::YUZU_PAGEBITS;
531 539
532 if (delta > 0) { 540 if (vpage == 0) [[unlikely]] {
533 ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits<u8>::max(), 541 release_pending();
534 "Count may overflow!"); 542 continue;
535 } else if (delta < 0) { 543 }
536 ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!"); 544
537 } else { 545 if (asid.id != asid_2.id) [[unlikely]] {
538 ASSERT_MSG(false, "Delta must be non-zero!"); 546 release_pending();
547 memory_device_inter = registered_processes[asid_2.id];
539 } 548 }
540 549
541 // Adds or subtracts 1, as count is a unsigned 8-bit value 550 // Adds or subtracts 1, as count is a unsigned 8-bit value
542 count.fetch_add(static_cast<u8>(delta), std::memory_order_release); 551 count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release);
543 552
544 // Assume delta is either -1 or 1 553 // Assume delta is either -1 or 1
545 if (count.load(std::memory_order::relaxed) == 0) { 554 if (count.load(std::memory_order::relaxed) == 0) {
@@ -548,7 +557,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
548 } 557 }
549 uncache_bytes += Memory::YUZU_PAGESIZE; 558 uncache_bytes += Memory::YUZU_PAGESIZE;
550 } else if (uncache_bytes > 0) { 559 } else if (uncache_bytes > 0) {
551 Lock();
552 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, 560 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
553 uncache_bytes, false); 561 uncache_bytes, false);
554 uncache_bytes = 0; 562 uncache_bytes = 0;
@@ -559,23 +567,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
559 } 567 }
560 cache_bytes += Memory::YUZU_PAGESIZE; 568 cache_bytes += Memory::YUZU_PAGESIZE;
561 } else if (cache_bytes > 0) { 569 } else if (cache_bytes > 0) {
562 Lock(); 570 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
563 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, 571 cache_bytes, true);
564 true);
565 cache_bytes = 0; 572 cache_bytes = 0;
566 } 573 }
567 vpage++;
568 }
569 if (uncache_bytes > 0) {
570 Lock();
571 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
572 false);
573 }
574 if (cache_bytes > 0) {
575 Lock();
576 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
577 true);
578 } 574 }
575 release_pending();
579} 576}
580 577
581} // namespace Core 578} // 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 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/frontend/applets/general_frontend.h" 5#include "core/frontend/applets/general.h"
6 6
7namespace Core::Frontend { 7namespace Core::Frontend {
8 8
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 @@
8 8
9#include "common/uuid.h" 9#include "common/uuid.h"
10#include "core/frontend/applets/applet.h" 10#include "core/frontend/applets/applet.h"
11#include "core/hle/service/am/applets/applet_profile_select.h" 11#include "core/hle/service/am/frontend/applet_profile_select.h"
12 12
13namespace Core::Frontend { 13namespace Core::Frontend {
14 14
15struct ProfileSelectParameters { 15struct ProfileSelectParameters {
16 Service::AM::Applets::UiMode mode; 16 Service::AM::Frontend::UiMode mode;
17 std::array<Common::UUID, 8> invalid_uid_list; 17 std::array<Common::UUID, 8> invalid_uid_list;
18 Service::AM::Applets::UiSettingsDisplayOptions display_options; 18 Service::AM::Frontend::UiSettingsDisplayOptions display_options;
19 Service::AM::Applets::UserSelectionPurpose purpose; 19 Service::AM::Frontend::UserSelectionPurpose purpose;
20}; 20};
21 21
22class ProfileSelectApplet : public Applet { 22class 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 {
69} 69}
70 70
71void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog( 71void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
72 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 72 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
73 std::u16string text_check_message) const { 73 std::u16string text_check_message) const {
74 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog."); 74 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
75} 75}
@@ -118,7 +118,7 @@ void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_
118 "\ncursor_position={}", 118 "\ncursor_position={}",
119 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position); 119 Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
120 120
121 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, 121 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
122 text_parameters.input_text, text_parameters.cursor_position); 122 text_parameters.input_text, text_parameters.cursor_position);
123} 123}
124 124
@@ -127,22 +127,22 @@ void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
127} 127}
128 128
129void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const { 129void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
130 submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text, true); 130 submit_normal_callback(Service::AM::Frontend::SwkbdResult::Ok, text, true);
131} 131}
132 132
133void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const { 133void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
134 std::this_thread::sleep_for(std::chrono::milliseconds(500)); 134 std::this_thread::sleep_for(std::chrono::milliseconds(500));
135 135
136 for (std::size_t index = 0; index < text.size(); ++index) { 136 for (std::size_t index = 0; index < text.size(); ++index) {
137 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString, 137 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString,
138 std::u16string(text.data(), text.data() + index + 1), 138 std::u16string(text.data(), text.data() + index + 1),
139 static_cast<s32>(index) + 1); 139 static_cast<s32>(index) + 1);
140 140
141 std::this_thread::sleep_for(std::chrono::milliseconds(250)); 141 std::this_thread::sleep_for(std::chrono::milliseconds(250));
142 } 142 }
143 143
144 submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text), 144 submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::DecidedEnter,
145 static_cast<s32>(text.size())); 145 std::u16string(text), static_cast<s32>(text.size()));
146} 146}
147 147
148} // namespace Core::Frontend 148} // 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 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9 9
10#include "core/frontend/applets/applet.h" 10#include "core/frontend/applets/applet.h"
11#include "core/hle/service/am/applets/applet_software_keyboard_types.h" 11#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
12 12
13namespace Core::Frontend { 13namespace Core::Frontend {
14 14
@@ -23,10 +23,10 @@ struct KeyboardInitializeParameters {
23 u32 max_text_length; 23 u32 max_text_length;
24 u32 min_text_length; 24 u32 min_text_length;
25 s32 initial_cursor_position; 25 s32 initial_cursor_position;
26 Service::AM::Applets::SwkbdType type; 26 Service::AM::Frontend::SwkbdType type;
27 Service::AM::Applets::SwkbdPasswordMode password_mode; 27 Service::AM::Frontend::SwkbdPasswordMode password_mode;
28 Service::AM::Applets::SwkbdTextDrawType text_draw_type; 28 Service::AM::Frontend::SwkbdTextDrawType text_draw_type;
29 Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; 29 Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
30 bool use_blur_background; 30 bool use_blur_background;
31 bool enable_backspace_button; 31 bool enable_backspace_button;
32 bool enable_return_button; 32 bool enable_return_button;
@@ -40,8 +40,8 @@ struct InlineAppearParameters {
40 f32 key_top_scale_y; 40 f32 key_top_scale_y;
41 f32 key_top_translate_x; 41 f32 key_top_translate_x;
42 f32 key_top_translate_y; 42 f32 key_top_translate_y;
43 Service::AM::Applets::SwkbdType type; 43 Service::AM::Frontend::SwkbdType type;
44 Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags; 44 Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
45 bool key_top_as_floating; 45 bool key_top_as_floating;
46 bool enable_backspace_button; 46 bool enable_backspace_button;
47 bool enable_return_button; 47 bool enable_return_button;
@@ -56,9 +56,9 @@ struct InlineTextParameters {
56class SoftwareKeyboardApplet : public Applet { 56class SoftwareKeyboardApplet : public Applet {
57public: 57public:
58 using SubmitInlineCallback = 58 using SubmitInlineCallback =
59 std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>; 59 std::function<void(Service::AM::Frontend::SwkbdReplyType, std::u16string, s32)>;
60 using SubmitNormalCallback = 60 using SubmitNormalCallback =
61 std::function<void(Service::AM::Applets::SwkbdResult, std::u16string, bool)>; 61 std::function<void(Service::AM::Frontend::SwkbdResult, std::u16string, bool)>;
62 62
63 virtual ~SoftwareKeyboardApplet(); 63 virtual ~SoftwareKeyboardApplet();
64 64
@@ -69,7 +69,7 @@ public:
69 69
70 virtual void ShowNormalKeyboard() const = 0; 70 virtual void ShowNormalKeyboard() const = 0;
71 71
72 virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 72 virtual void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
73 std::u16string text_check_message) const = 0; 73 std::u16string text_check_message) const = 0;
74 74
75 virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0; 75 virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;
@@ -93,7 +93,7 @@ public:
93 93
94 void ShowNormalKeyboard() const override; 94 void ShowNormalKeyboard() const override;
95 95
96 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 96 void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
97 std::u16string text_check_message) const override; 97 std::u16string text_check_message) const override;
98 98
99 void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override; 99 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,
18 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}", 18 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
19 local_url); 19 local_url);
20 20
21 callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); 21 callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
22} 22}
23 23
24void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url, 24void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_url,
@@ -26,7 +26,7 @@ void DefaultWebBrowserApplet::OpenExternalWebPage(const std::string& external_ur
26 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}", 26 LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
27 external_url); 27 external_url);
28 28
29 callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); 29 callback(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
30} 30}
31 31
32} // namespace Core::Frontend 32} // 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 @@
6#include <functional> 6#include <functional>
7 7
8#include "core/frontend/applets/applet.h" 8#include "core/frontend/applets/applet.h"
9#include "core/hle/service/am/applets/applet_web_browser_types.h" 9#include "core/hle/service/am/frontend/applet_web_browser_types.h"
10 10
11namespace Core::Frontend { 11namespace Core::Frontend {
12 12
@@ -14,7 +14,7 @@ class WebBrowserApplet : public Applet {
14public: 14public:
15 using ExtractROMFSCallback = std::function<void()>; 15 using ExtractROMFSCallback = std::function<void()>;
16 using OpenWebPageCallback = 16 using OpenWebPageCallback =
17 std::function<void(Service::AM::Applets::WebExitReason, std::string)>; 17 std::function<void(Service::AM::Frontend::WebExitReason, std::string)>;
18 18
19 virtual ~WebBrowserApplet(); 19 virtual ~WebBrowserApplet();
20 20
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 {
97 RegisterHostThread(nullptr); 97 RegisterHostThread(nullptr);
98 } 98 }
99 99
100 void TerminateApplicationProcess() { 100 void TerminateAllProcesses() {
101 application_process.load()->Terminate(); 101 std::scoped_lock lk{process_list_lock};
102 for (auto& process : process_list) {
103 process->Terminate();
104 process->Close();
105 process = nullptr;
106 }
107 process_list.clear();
102 } 108 }
103 109
104 void Shutdown() { 110 void Shutdown() {
@@ -107,18 +113,9 @@ struct KernelCore::Impl {
107 113
108 CloseServices(); 114 CloseServices();
109 115
110 auto* old_process = application_process.exchange(nullptr); 116 if (application_process) {
111 if (old_process) { 117 application_process->Close();
112 old_process->Close(); 118 application_process = nullptr;
113 }
114
115 {
116 std::scoped_lock lk{process_list_lock};
117 for (auto* const process : process_list) {
118 process->Terminate();
119 process->Close();
120 }
121 process_list.clear();
122 } 119 }
123 120
124 next_object_id = 0; 121 next_object_id = 0;
@@ -354,6 +351,7 @@ struct KernelCore::Impl {
354 351
355 void MakeApplicationProcess(KProcess* process) { 352 void MakeApplicationProcess(KProcess* process) {
356 application_process = process; 353 application_process = process;
354 application_process->Open();
357 } 355 }
358 356
359 static inline thread_local u8 host_thread_id = UINT8_MAX; 357 static inline thread_local u8 host_thread_id = UINT8_MAX;
@@ -779,7 +777,7 @@ struct KernelCore::Impl {
779 // Lists all processes that exist in the current session. 777 // Lists all processes that exist in the current session.
780 std::mutex process_list_lock; 778 std::mutex process_list_lock;
781 std::vector<KProcess*> process_list; 779 std::vector<KProcess*> process_list;
782 std::atomic<KProcess*> application_process{}; 780 KProcess* application_process{};
783 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; 781 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
784 std::unique_ptr<Kernel::KHardwareTimer> hardware_timer; 782 std::unique_ptr<Kernel::KHardwareTimer> hardware_timer;
785 783
@@ -1243,7 +1241,7 @@ void KernelCore::SuspendApplication(bool suspended) {
1243} 1241}
1244 1242
1245void KernelCore::ShutdownCores() { 1243void KernelCore::ShutdownCores() {
1246 impl->TerminateApplicationProcess(); 1244 impl->TerminateAllProcesses();
1247 1245
1248 KScopedSchedulerLock lk{*this}; 1246 KScopedSchedulerLock lk{*this};
1249 1247
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index a768bdc54..8f90eba34 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1,2704 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <algorithm>
5#include <array>
6#include <cinttypes>
7#include <cstring>
8#include "common/settings.h"
9#include "common/settings_enums.h"
10#include "core/core.h"
11#include "core/core_timing.h"
12#include "core/file_sys/control_metadata.h"
13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/registered_cache.h"
15#include "core/file_sys/savedata_factory.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/kernel/k_transfer_memory.h"
18#include "core/hle/result.h"
19#include "core/hle/service/acc/profile_manager.h"
20#include "core/hle/service/am/am.h" 4#include "core/hle/service/am/am.h"
21#include "core/hle/service/am/applet_ae.h" 5#include "core/hle/service/am/applet_ae.h"
22#include "core/hle/service/am/applet_oe.h" 6#include "core/hle/service/am/applet_oe.h"
23#include "core/hle/service/am/applets/applet_cabinet.h"
24#include "core/hle/service/am/applets/applet_controller.h"
25#include "core/hle/service/am/applets/applet_mii_edit_types.h"
26#include "core/hle/service/am/applets/applet_profile_select.h"
27#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
28#include "core/hle/service/am/applets/applet_web_browser.h"
29#include "core/hle/service/am/applets/applets.h"
30#include "core/hle/service/am/idle.h" 7#include "core/hle/service/am/idle.h"
31#include "core/hle/service/am/omm.h" 8#include "core/hle/service/am/omm.h"
32#include "core/hle/service/am/spsm.h" 9#include "core/hle/service/am/spsm.h"
33#include "core/hle/service/apm/apm_controller.h"
34#include "core/hle/service/apm/apm_interface.h"
35#include "core/hle/service/bcat/backend/backend.h"
36#include "core/hle/service/caps/caps_su.h"
37#include "core/hle/service/caps/caps_types.h"
38#include "core/hle/service/filesystem/filesystem.h"
39#include "core/hle/service/filesystem/save_data_controller.h"
40#include "core/hle/service/ipc_helpers.h"
41#include "core/hle/service/ns/ns.h"
42#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
43#include "core/hle/service/nvnflinger/nvnflinger.h"
44#include "core/hle/service/pm/pm.h"
45#include "core/hle/service/server_manager.h" 10#include "core/hle/service/server_manager.h"
46#include "core/hle/service/sm/sm.h"
47#include "core/hle/service/vi/vi.h"
48#include "core/hle/service/vi/vi_results.h"
49#include "core/memory.h"
50#include "hid_core/hid_types.h"
51#include "hid_core/resources/npad/npad.h"
52 11
53namespace Service::AM { 12namespace Service::AM {
54 13
55constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
56constexpr Result ResultNoMessages{ErrorModule::AM, 3};
57constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
58
59enum class LaunchParameterKind : u32 {
60 UserChannel = 1,
61 AccountPreselectedUser = 2,
62};
63
64constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA;
65
66struct LaunchParameterAccountPreselectedUser {
67 u32_le magic;
68 u32_le is_account_selected;
69 Common::UUID current_user;
70 INSERT_PADDING_BYTES(0x70);
71};
72static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
73
74IWindowController::IWindowController(Core::System& system_)
75 : ServiceFramework{system_, "IWindowController"} {
76 // clang-format off
77 static const FunctionInfo functions[] = {
78 {0, nullptr, "CreateWindow"},
79 {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
80 {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"},
81 {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
82 {11, nullptr, "ReleaseForegroundRights"},
83 {12, nullptr, "RejectToChangeIntoBackground"},
84 {20, nullptr, "SetAppletWindowVisibility"},
85 {21, nullptr, "SetAppletGpuTimeSlice"},
86 };
87 // clang-format on
88
89 RegisterHandlers(functions);
90}
91
92IWindowController::~IWindowController() = default;
93
94void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) {
95 const u64 process_id = system.ApplicationProcess()->GetProcessId();
96
97 LOG_DEBUG(Service_AM, "called. Process ID=0x{:016X}", process_id);
98
99 IPC::ResponseBuilder rb{ctx, 4};
100 rb.Push(ResultSuccess);
101 rb.Push<u64>(process_id);
102}
103
104void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) {
105 const u64 process_id = 0;
106
107 LOG_WARNING(Service_AM, "(STUBBED) called");
108
109 IPC::ResponseBuilder rb{ctx, 4};
110 rb.Push(ResultSuccess);
111 rb.Push<u64>(process_id);
112}
113
114void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
115 LOG_WARNING(Service_AM, "(STUBBED) called");
116 IPC::ResponseBuilder rb{ctx, 2};
117 rb.Push(ResultSuccess);
118}
119
120IAudioController::IAudioController(Core::System& system_)
121 : ServiceFramework{system_, "IAudioController"} {
122 // clang-format off
123 static const FunctionInfo functions[] = {
124 {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"},
125 {1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"},
126 {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"},
127 {3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"},
128 {4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"},
129 };
130 // clang-format on
131
132 RegisterHandlers(functions);
133}
134
135IAudioController::~IAudioController() = default;
136
137void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) {
138 IPC::RequestParser rp{ctx};
139 const float main_applet_volume_tmp = rp.Pop<float>();
140 const float library_applet_volume_tmp = rp.Pop<float>();
141
142 LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
143 main_applet_volume_tmp, library_applet_volume_tmp);
144
145 // Ensure the volume values remain within the 0-100% range
146 main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
147 library_applet_volume =
148 std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
149
150 IPC::ResponseBuilder rb{ctx, 2};
151 rb.Push(ResultSuccess);
152}
153
154void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) {
155 LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume);
156 IPC::ResponseBuilder rb{ctx, 3};
157 rb.Push(ResultSuccess);
158 rb.Push(main_applet_volume);
159}
160
161void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) {
162 LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume);
163 IPC::ResponseBuilder rb{ctx, 3};
164 rb.Push(ResultSuccess);
165 rb.Push(library_applet_volume);
166}
167
168void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) {
169 struct Parameters {
170 float volume;
171 s64 fade_time_ns;
172 };
173 static_assert(sizeof(Parameters) == 16);
174
175 IPC::RequestParser rp{ctx};
176 const auto parameters = rp.PopRaw<Parameters>();
177
178 LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume,
179 parameters.fade_time_ns);
180
181 main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume);
182 fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns};
183
184 IPC::ResponseBuilder rb{ctx, 2};
185 rb.Push(ResultSuccess);
186}
187
188void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) {
189 IPC::RequestParser rp{ctx};
190 const float transparent_volume_rate_tmp = rp.Pop<float>();
191
192 LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp);
193
194 // Clamp volume range to 0-100%.
195 transparent_volume_rate =
196 std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume);
197
198 IPC::ResponseBuilder rb{ctx, 2};
199 rb.Push(ResultSuccess);
200}
201
202IDisplayController::IDisplayController(Core::System& system_)
203 : ServiceFramework{system_, "IDisplayController"} {
204 // clang-format off
205 static const FunctionInfo functions[] = {
206 {0, nullptr, "GetLastForegroundCaptureImage"},
207 {1, nullptr, "UpdateLastForegroundCaptureImage"},
208 {2, nullptr, "GetLastApplicationCaptureImage"},
209 {3, nullptr, "GetCallerAppletCaptureImage"},
210 {4, nullptr, "UpdateCallerAppletCaptureImage"},
211 {5, nullptr, "GetLastForegroundCaptureImageEx"},
212 {6, nullptr, "GetLastApplicationCaptureImageEx"},
213 {7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"},
214 {8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
215 {9, nullptr, "CopyBetweenCaptureBuffers"},
216 {10, nullptr, "AcquireLastApplicationCaptureBuffer"},
217 {11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
218 {12, nullptr, "AcquireLastForegroundCaptureBuffer"},
219 {13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
220 {14, nullptr, "AcquireCallerAppletCaptureBuffer"},
221 {15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
222 {16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
223 {17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
224 {18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
225 {20, nullptr, "ClearCaptureBuffer"},
226 {21, nullptr, "ClearAppletTransitionBuffer"},
227 {22, nullptr, "AcquireLastApplicationCaptureSharedBuffer"},
228 {23, nullptr, "ReleaseLastApplicationCaptureSharedBuffer"},
229 {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"},
230 {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"},
231 {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
232 {27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
233 {28, nullptr, "TakeScreenShotOfOwnLayerEx"},
234 };
235 // clang-format on
236
237 RegisterHandlers(functions);
238}
239
240IDisplayController::~IDisplayController() = default;
241
242void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) {
243 LOG_WARNING(Service_AM, "(STUBBED) called");
244
245 IPC::ResponseBuilder rb{ctx, 4};
246 rb.Push(ResultSuccess);
247 rb.Push(1u);
248 rb.Push(0);
249}
250
251void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
252 LOG_WARNING(Service_AM, "(STUBBED) called");
253
254 IPC::ResponseBuilder rb{ctx, 2};
255 rb.Push(ResultSuccess);
256}
257
258void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
259 LOG_WARNING(Service_AM, "(STUBBED) called");
260
261 IPC::ResponseBuilder rb{ctx, 4};
262 rb.Push(ResultSuccess);
263 rb.Push(1U);
264 rb.Push(0);
265}
266
267void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
268 LOG_WARNING(Service_AM, "(STUBBED) called");
269
270 IPC::ResponseBuilder rb{ctx, 2};
271 rb.Push(ResultSuccess);
272}
273
274void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
275 LOG_WARNING(Service_AM, "(STUBBED) called");
276
277 IPC::ResponseBuilder rb{ctx, 4};
278 rb.Push(ResultSuccess);
279 rb.Push(1U);
280 rb.Push(0);
281}
282
283void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
284 LOG_WARNING(Service_AM, "(STUBBED) called");
285
286 IPC::ResponseBuilder rb{ctx, 2};
287 rb.Push(ResultSuccess);
288}
289
290IDebugFunctions::IDebugFunctions(Core::System& system_)
291 : ServiceFramework{system_, "IDebugFunctions"} {
292 // clang-format off
293 static const FunctionInfo functions[] = {
294 {0, nullptr, "NotifyMessageToHomeMenuForDebug"},
295 {1, nullptr, "OpenMainApplication"},
296 {10, nullptr, "PerformSystemButtonPressing"},
297 {20, nullptr, "InvalidateTransitionLayer"},
298 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
299 {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
300 {40, nullptr, "GetAppletResourceUsageInfo"},
301 {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
302 {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
303 {100, nullptr, "SetCpuBoostModeForApplet"},
304 {101, nullptr, "CancelCpuBoostModeForApplet"},
305 {110, nullptr, "PushToAppletBoundChannelForDebug"},
306 {111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
307 {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
308 {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
309 {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
310 {130, nullptr, "FriendInvitationSetApplicationParameter"},
311 {131, nullptr, "FriendInvitationClearApplicationParameter"},
312 {132, nullptr, "FriendInvitationPushApplicationParameter"},
313 {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
314 {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
315 {300, nullptr, "TerminateAllRunningApplicationsForDebug"},
316 {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
317 };
318 // clang-format on
319
320 RegisterHandlers(functions);
321}
322
323IDebugFunctions::~IDebugFunctions() = default;
324
325ISelfController::ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_)
326 : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_},
327 service_context{system, "ISelfController"} {
328 // clang-format off
329 static const FunctionInfo functions[] = {
330 {0, &ISelfController::Exit, "Exit"},
331 {1, &ISelfController::LockExit, "LockExit"},
332 {2, &ISelfController::UnlockExit, "UnlockExit"},
333 {3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
334 {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"},
335 {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
336 {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
337 {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
338 {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"},
339 {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
340 {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
341 {15, nullptr, "SetScreenShotAppletIdentityInfo"},
342 {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
343 {17, nullptr, "SetControllerFirmwareUpdateSection"},
344 {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
345 {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"},
346 {20, nullptr, "SetDesirableKeyboardLayout"},
347 {21, nullptr, "GetScreenShotProgramId"},
348 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
349 {41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"},
350 {42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"},
351 {43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"},
352 {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
353 {45, nullptr, "SetManagedDisplayLayerSeparationMode"},
354 {46, nullptr, "SetRecordingLayerCompositionEnabled"},
355 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
356 {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
357 {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
358 {61, nullptr, "SetMediaPlaybackState"},
359 {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
360 {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
361 {64, nullptr, "SetInputDetectionSourceSet"},
362 {65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"},
363 {66, nullptr, "GetCurrentIlluminance"},
364 {67, nullptr, "IsIlluminanceAvailable"},
365 {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"},
366 {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
367 {70, nullptr, "ReportMultimediaError"},
368 {71, nullptr, "GetCurrentIlluminanceEx"},
369 {72, nullptr, "SetInputDetectionPolicy"},
370 {80, nullptr, "SetWirelessPriorityMode"},
371 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
372 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
373 {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
374 {110, nullptr, "SetApplicationAlbumUserData"},
375 {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"},
376 {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"},
377 {1000, nullptr, "GetDebugStorageChannel"},
378 };
379 // clang-format on
380
381 RegisterHandlers(functions);
382
383 launchable_event = service_context.CreateEvent("ISelfController:LaunchableEvent");
384
385 // This event is created by AM on the first time GetAccumulatedSuspendedTickChangedEvent() is
386 // called. Yuzu can just create it unconditionally, since it doesn't need to support multiple
387 // ISelfControllers. The event is signaled on creation, and on transition from suspended -> not
388 // suspended if the event has previously been created by a call to
389 // GetAccumulatedSuspendedTickChangedEvent.
390
391 accumulated_suspended_tick_changed_event =
392 service_context.CreateEvent("ISelfController:AccumulatedSuspendedTickChangedEvent");
393 accumulated_suspended_tick_changed_event->Signal();
394}
395
396ISelfController::~ISelfController() {
397 service_context.CloseEvent(launchable_event);
398 service_context.CloseEvent(accumulated_suspended_tick_changed_event);
399}
400
401void ISelfController::Exit(HLERequestContext& ctx) {
402 LOG_DEBUG(Service_AM, "called");
403
404 IPC::ResponseBuilder rb{ctx, 2};
405 rb.Push(ResultSuccess);
406
407 system.Exit();
408}
409
410void ISelfController::LockExit(HLERequestContext& ctx) {
411 LOG_DEBUG(Service_AM, "called");
412
413 system.SetExitLocked(true);
414
415 IPC::ResponseBuilder rb{ctx, 2};
416 rb.Push(ResultSuccess);
417}
418
419void ISelfController::UnlockExit(HLERequestContext& ctx) {
420 LOG_DEBUG(Service_AM, "called");
421
422 system.SetExitLocked(false);
423
424 IPC::ResponseBuilder rb{ctx, 2};
425 rb.Push(ResultSuccess);
426
427 if (system.GetExitRequested()) {
428 system.Exit();
429 }
430}
431
432void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
433 ++num_fatal_sections_entered;
434 LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", num_fatal_sections_entered);
435
436 IPC::ResponseBuilder rb{ctx, 2};
437 rb.Push(ResultSuccess);
438}
439
440void ISelfController::LeaveFatalSection(HLERequestContext& ctx) {
441 LOG_DEBUG(Service_AM, "called.");
442
443 // Entry and exit of fatal sections must be balanced.
444 if (num_fatal_sections_entered == 0) {
445 IPC::ResponseBuilder rb{ctx, 2};
446 rb.Push(Result{ErrorModule::AM, 512});
447 return;
448 }
449
450 --num_fatal_sections_entered;
451
452 IPC::ResponseBuilder rb{ctx, 2};
453 rb.Push(ResultSuccess);
454}
455
456void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) {
457 LOG_WARNING(Service_AM, "(STUBBED) called");
458
459 launchable_event->Signal();
460
461 IPC::ResponseBuilder rb{ctx, 2, 1};
462 rb.Push(ResultSuccess);
463 rb.PushCopyObjects(launchable_event->GetReadableEvent());
464}
465
466void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) {
467 IPC::RequestParser rp{ctx};
468 const auto permission = rp.PopEnum<ScreenshotPermission>();
469 LOG_DEBUG(Service_AM, "called, permission={}", permission);
470
471 screenshot_permission = permission;
472
473 IPC::ResponseBuilder rb{ctx, 2};
474 rb.Push(ResultSuccess);
475}
476
477void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) {
478 IPC::RequestParser rp{ctx};
479
480 bool flag = rp.Pop<bool>();
481 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
482
483 IPC::ResponseBuilder rb{ctx, 2};
484 rb.Push(ResultSuccess);
485}
486
487void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) {
488 IPC::RequestParser rp{ctx};
489
490 bool flag = rp.Pop<bool>();
491 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
492
493 IPC::ResponseBuilder rb{ctx, 2};
494 rb.Push(ResultSuccess);
495}
496
497void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) {
498 // Takes 3 input u8s with each field located immediately after the previous
499 // u8, these are bool flags. No output.
500 IPC::RequestParser rp{ctx};
501
502 struct FocusHandlingModeParams {
503 u8 unknown0;
504 u8 unknown1;
505 u8 unknown2;
506 };
507 const auto flags = rp.PopRaw<FocusHandlingModeParams>();
508
509 LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}",
510 flags.unknown0, flags.unknown1, flags.unknown2);
511
512 IPC::ResponseBuilder rb{ctx, 2};
513 rb.Push(ResultSuccess);
514}
515
516void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) {
517 LOG_WARNING(Service_AM, "(STUBBED) called");
518
519 IPC::ResponseBuilder rb{ctx, 2};
520 rb.Push(ResultSuccess);
521}
522
523void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) {
524 // Takes 3 input u8s with each field located immediately after the previous
525 // u8, these are bool flags. No output.
526 IPC::RequestParser rp{ctx};
527
528 bool enabled = rp.Pop<bool>();
529 LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
530
531 IPC::ResponseBuilder rb{ctx, 2};
532 rb.Push(ResultSuccess);
533}
534
535void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) {
536 LOG_WARNING(Service_AM, "(STUBBED) called");
537
538 IPC::ResponseBuilder rb{ctx, 2};
539 rb.Push(ResultSuccess);
540}
541
542void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
543 LOG_WARNING(Service_AM, "(STUBBED) called");
544
545 // TODO(Subv): Find out how AM determines the display to use, for now just
546 // create the layer in the Default display.
547 const auto display_id = nvnflinger.OpenDisplay("Default");
548 const auto layer_id = nvnflinger.CreateLayer(*display_id);
549
550 IPC::ResponseBuilder rb{ctx, 4};
551 rb.Push(ResultSuccess);
552 rb.Push(*layer_id);
553}
554
555void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) {
556 LOG_WARNING(Service_AM, "(STUBBED) called");
557
558 IPC::ResponseBuilder rb{ctx, 2};
559 rb.Push(this->EnsureBufferSharingEnabled());
560}
561
562void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) {
563 LOG_WARNING(Service_AM, "(STUBBED) called");
564
565 IPC::ResponseBuilder rb{ctx, 6};
566 rb.Push(this->EnsureBufferSharingEnabled());
567 rb.Push<s64>(system_shared_buffer_id);
568 rb.Push<s64>(system_shared_layer_id);
569}
570
571void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
572 LOG_WARNING(Service_AM, "(STUBBED) called");
573
574 IPC::ResponseBuilder rb{ctx, 4};
575 rb.Push(this->EnsureBufferSharingEnabled());
576 rb.Push<s64>(system_shared_buffer_id);
577}
578
579Result ISelfController::EnsureBufferSharingEnabled() {
580 if (buffer_sharing_enabled) {
581 return ResultSuccess;
582 }
583
584 if (system.GetAppletManager().GetCurrentAppletId() <= Applets::AppletId::Application) {
585 return VI::ResultOperationFailed;
586 }
587
588 const auto display_id = nvnflinger.OpenDisplay("Default");
589 const auto result = nvnflinger.GetSystemBufferManager().Initialize(
590 &system_shared_buffer_id, &system_shared_layer_id, *display_id);
591
592 if (result.IsSuccess()) {
593 buffer_sharing_enabled = true;
594 }
595
596 return result;
597}
598
599void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
600 LOG_WARNING(Service_AM, "(STUBBED) called");
601
602 // TODO(Subv): Find out how AM determines the display to use, for now just
603 // create the layer in the Default display.
604 // This calls nn::vi::CreateRecordingLayer() which creates another layer.
605 // Currently we do not support more than 1 layer per display, output 1 layer id for now.
606 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
607 // side effects.
608 // TODO: Support multiple layers
609 const auto display_id = nvnflinger.OpenDisplay("Default");
610 const auto layer_id = nvnflinger.CreateLayer(*display_id);
611
612 IPC::ResponseBuilder rb{ctx, 4};
613 rb.Push(ResultSuccess);
614 rb.Push(*layer_id);
615}
616
617void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
618 LOG_WARNING(Service_AM, "(STUBBED) called");
619
620 IPC::ResponseBuilder rb{ctx, 2};
621 rb.Push(ResultSuccess);
622}
623
624void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
625 LOG_WARNING(Service_AM, "(STUBBED) called");
626
627 IPC::ResponseBuilder rb{ctx, 2};
628 rb.Push(ResultSuccess);
629}
630
631void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
632 IPC::RequestParser rp{ctx};
633 idle_time_detection_extension = rp.Pop<u32>();
634 LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
635 idle_time_detection_extension);
636
637 IPC::ResponseBuilder rb{ctx, 2};
638 rb.Push(ResultSuccess);
639}
640
641void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) {
642 LOG_WARNING(Service_AM, "(STUBBED) called");
643
644 IPC::ResponseBuilder rb{ctx, 3};
645 rb.Push(ResultSuccess);
646 rb.Push<u32>(idle_time_detection_extension);
647}
648
649void ISelfController::ReportUserIsActive(HLERequestContext& ctx) {
650 LOG_WARNING(Service_AM, "(STUBBED) called");
651
652 IPC::ResponseBuilder rb{ctx, 2};
653 rb.Push(ResultSuccess);
654}
655
656void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) {
657 IPC::RequestParser rp{ctx};
658 is_auto_sleep_disabled = rp.Pop<bool>();
659
660 // On the system itself, if the previous state of is_auto_sleep_disabled
661 // differed from the current value passed in, it'd signify the internal
662 // window manager to update (and also increment some statistics like update counts)
663 //
664 // It'd also indicate this change to an idle handling context.
665 //
666 // However, given we're emulating this behavior, most of this can be ignored
667 // and it's sufficient to simply set the member variable for querying via
668 // IsAutoSleepDisabled().
669
670 LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled);
671
672 IPC::ResponseBuilder rb{ctx, 2};
673 rb.Push(ResultSuccess);
674}
675
676void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) {
677 LOG_DEBUG(Service_AM, "called.");
678
679 IPC::ResponseBuilder rb{ctx, 3};
680 rb.Push(ResultSuccess);
681 rb.Push(is_auto_sleep_disabled);
682}
683
684void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) {
685 LOG_DEBUG(Service_AM, "called.");
686
687 // This command returns the total number of system ticks since ISelfController creation
688 // where the game was suspended. Since Yuzu doesn't implement game suspension, this command
689 // can just always return 0 ticks.
690 IPC::ResponseBuilder rb{ctx, 4};
691 rb.Push(ResultSuccess);
692 rb.Push<u64>(0);
693}
694
695void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) {
696 LOG_DEBUG(Service_AM, "called.");
697
698 IPC::ResponseBuilder rb{ctx, 2, 1};
699 rb.Push(ResultSuccess);
700 rb.PushCopyObjects(accumulated_suspended_tick_changed_event->GetReadableEvent());
701}
702
703void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) {
704 IPC::RequestParser rp{ctx};
705
706 // This service call sets an internal flag whether a notification is shown when an image is
707 // captured. Currently we do not support capturing images via the capture button, so this can be
708 // stubbed for now.
709 const bool album_image_taken_notification_enabled = rp.Pop<bool>();
710
711 LOG_WARNING(Service_AM, "(STUBBED) called. album_image_taken_notification_enabled={}",
712 album_image_taken_notification_enabled);
713
714 IPC::ResponseBuilder rb{ctx, 2};
715 rb.Push(ResultSuccess);
716}
717
718void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
719 IPC::RequestParser rp{ctx};
720
721 const auto report_option = rp.PopEnum<Capture::AlbumReportOption>();
722
723 LOG_INFO(Service_AM, "called, report_option={}", report_option);
724
725 const auto screenshot_service =
726 system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
727 "caps:su");
728
729 if (screenshot_service) {
730 screenshot_service->CaptureAndSaveScreenshot(report_option);
731 }
732
733 IPC::ResponseBuilder rb{ctx, 2};
734 rb.Push(ResultSuccess);
735}
736
737void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) {
738 IPC::RequestParser rp{ctx};
739
740 const auto is_record_volume_muted = rp.Pop<bool>();
741
742 LOG_WARNING(Service_AM, "(STUBBED) called. is_record_volume_muted={}", is_record_volume_muted);
743
744 IPC::ResponseBuilder rb{ctx, 2};
745 rb.Push(ResultSuccess);
746}
747
748AppletMessageQueue::AppletMessageQueue(Core::System& system)
749 : service_context{system, "AppletMessageQueue"} {
750 on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
751 on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
752}
753
754AppletMessageQueue::~AppletMessageQueue() {
755 service_context.CloseEvent(on_new_message);
756 service_context.CloseEvent(on_operation_mode_changed);
757}
758
759Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
760 return on_new_message->GetReadableEvent();
761}
762
763Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
764 return on_operation_mode_changed->GetReadableEvent();
765}
766
767void AppletMessageQueue::PushMessage(AppletMessage msg) {
768 messages.push(msg);
769 on_new_message->Signal();
770}
771
772AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
773 if (messages.empty()) {
774 on_new_message->Clear();
775 return AppletMessage::None;
776 }
777 auto msg = messages.front();
778 messages.pop();
779 if (messages.empty()) {
780 on_new_message->Clear();
781 }
782 return msg;
783}
784
785std::size_t AppletMessageQueue::GetMessageCount() const {
786 return messages.size();
787}
788
789void AppletMessageQueue::RequestExit() {
790 PushMessage(AppletMessage::Exit);
791}
792
793void AppletMessageQueue::RequestResume() {
794 PushMessage(AppletMessage::Resume);
795}
796
797void AppletMessageQueue::FocusStateChanged() {
798 PushMessage(AppletMessage::FocusStateChanged);
799}
800
801void AppletMessageQueue::OperationModeChanged() {
802 PushMessage(AppletMessage::OperationModeChanged);
803 PushMessage(AppletMessage::PerformanceModeChanged);
804 on_operation_mode_changed->Signal();
805}
806
807ILockAccessor::ILockAccessor(Core::System& system_)
808 : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
809 // clang-format off
810 static const FunctionInfo functions[] = {
811 {1, &ILockAccessor::TryLock, "TryLock"},
812 {2, &ILockAccessor::Unlock, "Unlock"},
813 {3, &ILockAccessor::GetEvent, "GetEvent"},
814 {4,&ILockAccessor::IsLocked, "IsLocked"},
815 };
816 // clang-format on
817
818 RegisterHandlers(functions);
819
820 lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
821}
822
823ILockAccessor::~ILockAccessor() {
824 service_context.CloseEvent(lock_event);
825};
826
827void ILockAccessor::TryLock(HLERequestContext& ctx) {
828 IPC::RequestParser rp{ctx};
829 const auto return_handle = rp.Pop<bool>();
830
831 LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
832
833 // TODO: When return_handle is true this function should return the lock handle
834
835 is_locked = true;
836
837 IPC::ResponseBuilder rb{ctx, 3};
838 rb.Push(ResultSuccess);
839 rb.Push<u8>(is_locked);
840}
841
842void ILockAccessor::Unlock(HLERequestContext& ctx) {
843 LOG_INFO(Service_AM, "called");
844
845 is_locked = false;
846
847 IPC::ResponseBuilder rb{ctx, 2};
848 rb.Push(ResultSuccess);
849}
850
851void ILockAccessor::GetEvent(HLERequestContext& ctx) {
852 LOG_INFO(Service_AM, "called");
853
854 lock_event->Signal();
855
856 IPC::ResponseBuilder rb{ctx, 2, 1};
857 rb.Push(ResultSuccess);
858 rb.PushCopyObjects(lock_event->GetReadableEvent());
859}
860
861void ILockAccessor::IsLocked(HLERequestContext& ctx) {
862 LOG_INFO(Service_AM, "called");
863
864 IPC::ResponseBuilder rb{ctx, 2};
865 rb.Push(ResultSuccess);
866 rb.Push<u8>(is_locked);
867}
868
869ICommonStateGetter::ICommonStateGetter(Core::System& system_,
870 std::shared_ptr<AppletMessageQueue> msg_queue_)
871 : ServiceFramework{system_, "ICommonStateGetter"}, msg_queue{std::move(msg_queue_)},
872 service_context{system_, "ICommonStateGetter"} {
873 // clang-format off
874 static const FunctionInfo functions[] = {
875 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
876 {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
877 {2, nullptr, "GetThisAppletKind"},
878 {3, nullptr, "AllowToEnterSleep"},
879 {4, nullptr, "DisallowToEnterSleep"},
880 {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"},
881 {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"},
882 {7, nullptr, "GetCradleStatus"},
883 {8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
884 {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
885 {10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"},
886 {11, nullptr, "ReleaseSleepLock"},
887 {12, nullptr, "ReleaseSleepLockTransiently"},
888 {13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"},
889 {14, nullptr, "GetWakeupCount"},
890 {20, nullptr, "PushToGeneralChannel"},
891 {30, nullptr, "GetHomeButtonReaderLockAccessor"},
892 {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
893 {32, nullptr, "GetWriterLockAccessorEx"},
894 {40, nullptr, "GetCradleFwVersion"},
895 {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
896 {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
897 {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
898 {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
899 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
900 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
901 {59, nullptr, "SetVrPositionForDebug"},
902 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
903 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
904 {62, nullptr, "GetHdcpAuthenticationState"},
905 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
906 {64, nullptr, "SetTvPowerStateMatchingMode"},
907 {65, nullptr, "GetApplicationIdByContentActionName"},
908 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
909 {67, nullptr, "CancelCpuBoostMode"},
910 {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
911 {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
912 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
913 {91, nullptr, "GetCurrentPerformanceConfiguration"},
914 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
915 {110, nullptr, "OpenMyGpuErrorHandler"},
916 {120, nullptr, "GetAppletLaunchedHistory"},
917 {200, nullptr, "GetOperationModeSystemInfo"},
918 {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"},
919 {400, nullptr, "ActivateMigrationService"},
920 {401, nullptr, "DeactivateMigrationService"},
921 {500, nullptr, "DisableSleepTillShutdown"},
922 {501, nullptr, "SuppressDisablingSleepTemporarily"},
923 {502, nullptr, "IsSleepEnabled"},
924 {503, nullptr, "IsDisablingSleepSuppressed"},
925 {900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
926 };
927 // clang-format on
928
929 RegisterHandlers(functions);
930
931 sleep_lock_event = service_context.CreateEvent("ICommonStateGetter::SleepLockEvent");
932
933 // Configure applets to be in foreground state
934 msg_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
935 msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
936}
937
938ICommonStateGetter::~ICommonStateGetter() {
939 service_context.CloseEvent(sleep_lock_event);
940};
941
942void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) {
943 LOG_DEBUG(Service_AM, "called");
944
945 IPC::ResponseBuilder rb{ctx, 3};
946 rb.Push(ResultSuccess);
947 rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
948}
949
950void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) {
951 LOG_DEBUG(Service_AM, "called");
952
953 IPC::ResponseBuilder rb{ctx, 2, 1};
954 rb.Push(ResultSuccess);
955 rb.PushCopyObjects(msg_queue->GetMessageReceiveEvent());
956}
957
958void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) {
959 LOG_DEBUG(Service_AM, "called");
960
961 const auto message = msg_queue->PopMessage();
962 IPC::ResponseBuilder rb{ctx, 3};
963
964 if (message == AppletMessageQueue::AppletMessage::None) {
965 LOG_ERROR(Service_AM, "Message queue is empty");
966 rb.Push(AM::ResultNoMessages);
967 rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
968 return;
969 }
970
971 rb.Push(ResultSuccess);
972 rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
973}
974
975void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
976 LOG_DEBUG(Service_AM, "(STUBBED) called");
977
978 IPC::ResponseBuilder rb{ctx, 3};
979 rb.Push(ResultSuccess);
980 rb.Push(static_cast<u8>(FocusState::InFocus));
981}
982
983void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
984 LOG_WARNING(Service_AM, "(STUBBED) called");
985
986 // Sleep lock is acquired immediately.
987 sleep_lock_event->Signal();
988
989 IPC::ResponseBuilder rb{ctx, 2};
990 rb.Push(ResultSuccess);
991}
992
993void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
994 IPC::RequestParser rp{ctx};
995 const auto unknown = rp.Pop<u32>();
996
997 LOG_INFO(Service_AM, "called, unknown={}", unknown);
998
999 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1000
1001 rb.Push(ResultSuccess);
1002 rb.PushIpcInterface<ILockAccessor>(system);
1003}
1004
1005void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
1006 LOG_WARNING(Service_AM, "called");
1007
1008 IPC::ResponseBuilder rb{ctx, 2, 1};
1009 rb.Push(ResultSuccess);
1010 rb.PushCopyObjects(sleep_lock_event->GetReadableEvent());
1011}
1012
1013void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
1014 LOG_DEBUG(Service_AM, "called");
1015
1016 IPC::ResponseBuilder rb{ctx, 3};
1017 rb.Push(ResultSuccess);
1018 rb.Push(vr_mode_state);
1019}
1020
1021void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) {
1022 IPC::RequestParser rp{ctx};
1023 vr_mode_state = rp.Pop<bool>();
1024
1025 LOG_WARNING(Service_AM, "VR Mode is {}", vr_mode_state ? "on" : "off");
1026
1027 IPC::ResponseBuilder rb{ctx, 2};
1028 rb.Push(ResultSuccess);
1029}
1030
1031void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) {
1032 IPC::RequestParser rp{ctx};
1033 const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
1034
1035 LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
1036 is_lcd_backlight_off_enabled);
1037
1038 IPC::ResponseBuilder rb{ctx, 2};
1039 rb.Push(ResultSuccess);
1040}
1041
1042void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) {
1043 LOG_WARNING(Service_AM, "(STUBBED) called");
1044
1045 IPC::ResponseBuilder rb{ctx, 2};
1046 rb.Push(ResultSuccess);
1047}
1048
1049void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) {
1050 LOG_WARNING(Service_AM, "(STUBBED) called");
1051
1052 IPC::ResponseBuilder rb{ctx, 2};
1053 rb.Push(ResultSuccess);
1054}
1055
1056void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) {
1057 LOG_DEBUG(Service_AM, "called");
1058
1059 IPC::ResponseBuilder rb{ctx, 2, 1};
1060 rb.Push(ResultSuccess);
1061 rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
1062}
1063
1064void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) {
1065 LOG_DEBUG(Service_AM, "called");
1066
1067 IPC::ResponseBuilder rb{ctx, 4};
1068 rb.Push(ResultSuccess);
1069
1070 if (Settings::IsDockedMode()) {
1071 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
1072 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
1073 } else {
1074 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
1075 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
1076 }
1077}
1078
1079void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
1080 LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
1081
1082 const auto& sm = system.ServiceManager();
1083 const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
1084 ASSERT(apm_sys != nullptr);
1085
1086 apm_sys->SetCpuBoostMode(ctx);
1087}
1088
1089void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
1090 LOG_WARNING(Service_AM, "(STUBBED) called");
1091
1092 IPC::ResponseBuilder rb{ctx, 3};
1093 rb.Push(ResultSuccess);
1094 rb.Push(0);
1095}
1096
1097void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
1098 IPC::RequestParser rp{ctx};
1099 const auto system_button{rp.PopEnum<SystemButtonType>()};
1100
1101 LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button);
1102
1103 IPC::ResponseBuilder rb{ctx, 2};
1104 rb.Push(ResultSuccess);
1105}
1106
1107void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) {
1108 LOG_WARNING(Service_AM, "(STUBBED) called");
1109
1110 IPC::ResponseBuilder rb{ctx, 3};
1111 rb.Push(ResultSuccess);
1112 rb.PushEnum(SysPlatformRegion::Global);
1113}
1114
1115void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(
1116 HLERequestContext& ctx) {
1117 LOG_WARNING(Service_AM, "(STUBBED) called");
1118
1119 IPC::ResponseBuilder rb{ctx, 2};
1120 rb.Push(ResultSuccess);
1121}
1122
1123IStorageImpl::~IStorageImpl() = default;
1124
1125class StorageDataImpl final : public IStorageImpl {
1126public:
1127 explicit StorageDataImpl(std::vector<u8>&& buffer_) : buffer{std::move(buffer_)} {}
1128
1129 std::vector<u8>& GetData() override {
1130 return buffer;
1131 }
1132
1133 const std::vector<u8>& GetData() const override {
1134 return buffer;
1135 }
1136
1137 std::size_t GetSize() const override {
1138 return buffer.size();
1139 }
1140
1141private:
1142 std::vector<u8> buffer;
1143};
1144
1145IStorage::IStorage(Core::System& system_, std::vector<u8>&& buffer)
1146 : ServiceFramework{system_, "IStorage"}, impl{std::make_shared<StorageDataImpl>(
1147 std::move(buffer))} {
1148 Register();
1149}
1150
1151void IStorage::Register() {
1152 // clang-format off
1153 static const FunctionInfo functions[] = {
1154 {0, &IStorage::Open, "Open"},
1155 {1, nullptr, "OpenTransferStorage"},
1156 };
1157 // clang-format on
1158
1159 RegisterHandlers(functions);
1160}
1161
1162IStorage::~IStorage() = default;
1163
1164void IStorage::Open(HLERequestContext& ctx) {
1165 LOG_DEBUG(Service_AM, "called");
1166
1167 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1168
1169 rb.Push(ResultSuccess);
1170 rb.PushIpcInterface<IStorageAccessor>(system, *this);
1171}
1172
1173void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) {
1174 const bool use_docked_mode{Settings::IsDockedMode()};
1175 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
1176
1177 IPC::ResponseBuilder rb{ctx, 3};
1178 rb.Push(ResultSuccess);
1179 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
1180}
1181
1182void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) {
1183 LOG_DEBUG(Service_AM, "called");
1184
1185 IPC::ResponseBuilder rb{ctx, 3};
1186 rb.Push(ResultSuccess);
1187 rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
1188}
1189
1190class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
1191public:
1192 explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<Applets::Applet> applet_)
1193 : ServiceFramework{system_, "ILibraryAppletAccessor"}, applet{std::move(applet_)} {
1194 // clang-format off
1195 static const FunctionInfo functions[] = {
1196 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
1197 {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
1198 {10, &ILibraryAppletAccessor::Start, "Start"},
1199 {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"},
1200 {25, nullptr, "Terminate"},
1201 {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
1202 {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
1203 {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"},
1204 {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
1205 {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
1206 {102, nullptr, "PushExtraStorage"},
1207 {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
1208 {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
1209 {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
1210 {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
1211 {110, nullptr, "NeedsToExitProcess"},
1212 {120, nullptr, "GetLibraryAppletInfo"},
1213 {150, nullptr, "RequestForAppletToGetForeground"},
1214 {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"},
1215 };
1216 // clang-format on
1217
1218 RegisterHandlers(functions);
1219 }
1220
1221private:
1222 void GetAppletStateChangedEvent(HLERequestContext& ctx) {
1223 LOG_DEBUG(Service_AM, "called");
1224
1225 IPC::ResponseBuilder rb{ctx, 2, 1};
1226 rb.Push(ResultSuccess);
1227 rb.PushCopyObjects(applet->GetBroker().GetStateChangedEvent());
1228 }
1229
1230 void IsCompleted(HLERequestContext& ctx) {
1231 LOG_DEBUG(Service_AM, "called");
1232
1233 IPC::ResponseBuilder rb{ctx, 3};
1234 rb.Push(ResultSuccess);
1235 rb.Push<u32>(applet->TransactionComplete());
1236 }
1237
1238 void GetResult(HLERequestContext& ctx) {
1239 LOG_DEBUG(Service_AM, "called");
1240
1241 IPC::ResponseBuilder rb{ctx, 2};
1242 rb.Push(applet->GetStatus());
1243 }
1244
1245 void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) {
1246 LOG_WARNING(Service_AM, "(STUBBED) called");
1247
1248 IPC::ResponseBuilder rb{ctx, 2};
1249 rb.Push(ResultSuccess);
1250 }
1251
1252 void Start(HLERequestContext& ctx) {
1253 LOG_DEBUG(Service_AM, "called");
1254
1255 ASSERT(applet != nullptr);
1256
1257 applet->Initialize();
1258 applet->Execute();
1259
1260 IPC::ResponseBuilder rb{ctx, 2};
1261 rb.Push(ResultSuccess);
1262 }
1263
1264 void RequestExit(HLERequestContext& ctx) {
1265 LOG_DEBUG(Service_AM, "called");
1266
1267 ASSERT(applet != nullptr);
1268
1269 IPC::ResponseBuilder rb{ctx, 2};
1270 rb.Push(applet->RequestExit());
1271 }
1272
1273 void PushInData(HLERequestContext& ctx) {
1274 LOG_DEBUG(Service_AM, "called");
1275
1276 IPC::RequestParser rp{ctx};
1277 applet->GetBroker().PushNormalDataFromGame(rp.PopIpcInterface<IStorage>().lock());
1278
1279 IPC::ResponseBuilder rb{ctx, 2};
1280 rb.Push(ResultSuccess);
1281 }
1282
1283 void PopOutData(HLERequestContext& ctx) {
1284 LOG_DEBUG(Service_AM, "called");
1285
1286 auto storage = applet->GetBroker().PopNormalDataToGame();
1287 if (storage == nullptr) {
1288 LOG_DEBUG(Service_AM,
1289 "storage is a nullptr. There is no data in the current normal channel");
1290 IPC::ResponseBuilder rb{ctx, 2};
1291 rb.Push(AM::ResultNoDataInChannel);
1292 return;
1293 }
1294
1295 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1296 rb.Push(ResultSuccess);
1297 rb.PushIpcInterface<IStorage>(std::move(storage));
1298 }
1299
1300 void PushInteractiveInData(HLERequestContext& ctx) {
1301 LOG_DEBUG(Service_AM, "called");
1302
1303 IPC::RequestParser rp{ctx};
1304 applet->GetBroker().PushInteractiveDataFromGame(rp.PopIpcInterface<IStorage>().lock());
1305
1306 ASSERT(applet->IsInitialized());
1307 applet->ExecuteInteractive();
1308 applet->Execute();
1309
1310 IPC::ResponseBuilder rb{ctx, 2};
1311 rb.Push(ResultSuccess);
1312 }
1313
1314 void PopInteractiveOutData(HLERequestContext& ctx) {
1315 LOG_DEBUG(Service_AM, "called");
1316
1317 auto storage = applet->GetBroker().PopInteractiveDataToGame();
1318 if (storage == nullptr) {
1319 LOG_DEBUG(Service_AM,
1320 "storage is a nullptr. There is no data in the current interactive channel");
1321 IPC::ResponseBuilder rb{ctx, 2};
1322 rb.Push(AM::ResultNoDataInChannel);
1323 return;
1324 }
1325
1326 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1327 rb.Push(ResultSuccess);
1328 rb.PushIpcInterface<IStorage>(std::move(storage));
1329 }
1330
1331 void GetPopOutDataEvent(HLERequestContext& ctx) {
1332 LOG_DEBUG(Service_AM, "called");
1333
1334 IPC::ResponseBuilder rb{ctx, 2, 1};
1335 rb.Push(ResultSuccess);
1336 rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
1337 }
1338
1339 void GetPopInteractiveOutDataEvent(HLERequestContext& ctx) {
1340 LOG_DEBUG(Service_AM, "called");
1341
1342 IPC::ResponseBuilder rb{ctx, 2, 1};
1343 rb.Push(ResultSuccess);
1344 rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
1345 }
1346
1347 void GetIndirectLayerConsumerHandle(HLERequestContext& ctx) {
1348 LOG_WARNING(Service_AM, "(STUBBED) called");
1349
1350 // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
1351 // actually used anywhere
1352 constexpr u64 handle = 0xdeadbeef;
1353
1354 IPC::ResponseBuilder rb{ctx, 4};
1355 rb.Push(ResultSuccess);
1356 rb.Push(handle);
1357 }
1358
1359 std::shared_ptr<Applets::Applet> applet;
1360};
1361
1362IStorageAccessor::IStorageAccessor(Core::System& system_, IStorage& backing_)
1363 : ServiceFramework{system_, "IStorageAccessor"}, backing{backing_} {
1364 // clang-format off
1365 static const FunctionInfo functions[] = {
1366 {0, &IStorageAccessor::GetSize, "GetSize"},
1367 {10, &IStorageAccessor::Write, "Write"},
1368 {11, &IStorageAccessor::Read, "Read"},
1369 };
1370 // clang-format on
1371
1372 RegisterHandlers(functions);
1373}
1374
1375IStorageAccessor::~IStorageAccessor() = default;
1376
1377void IStorageAccessor::GetSize(HLERequestContext& ctx) {
1378 LOG_DEBUG(Service_AM, "called");
1379
1380 IPC::ResponseBuilder rb{ctx, 4};
1381
1382 rb.Push(ResultSuccess);
1383 rb.Push(static_cast<u64>(backing.GetSize()));
1384}
1385
1386void IStorageAccessor::Write(HLERequestContext& ctx) {
1387 IPC::RequestParser rp{ctx};
1388
1389 const u64 offset{rp.Pop<u64>()};
1390 const auto data{ctx.ReadBuffer()};
1391 const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};
1392
1393 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
1394
1395 if (offset > backing.GetSize()) {
1396 LOG_ERROR(Service_AM,
1397 "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
1398 backing.GetSize(), size, offset);
1399
1400 IPC::ResponseBuilder rb{ctx, 2};
1401 rb.Push(AM::ResultInvalidOffset);
1402 return;
1403 }
1404
1405 std::memcpy(backing.GetData().data() + offset, data.data(), size);
1406
1407 IPC::ResponseBuilder rb{ctx, 2};
1408 rb.Push(ResultSuccess);
1409}
1410
1411void IStorageAccessor::Read(HLERequestContext& ctx) {
1412 IPC::RequestParser rp{ctx};
1413
1414 const u64 offset{rp.Pop<u64>()};
1415 const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};
1416
1417 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
1418
1419 if (offset > backing.GetSize()) {
1420 LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
1421 backing.GetSize(), size, offset);
1422
1423 IPC::ResponseBuilder rb{ctx, 2};
1424 rb.Push(AM::ResultInvalidOffset);
1425 return;
1426 }
1427
1428 ctx.WriteBuffer(backing.GetData().data() + offset, size);
1429
1430 IPC::ResponseBuilder rb{ctx, 2};
1431 rb.Push(ResultSuccess);
1432}
1433
1434ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
1435 : ServiceFramework{system_, "ILibraryAppletCreator"} {
1436 static const FunctionInfo functions[] = {
1437 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
1438 {1, nullptr, "TerminateAllLibraryApplets"},
1439 {2, nullptr, "AreAnyLibraryAppletsLeft"},
1440 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
1441 {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
1442 {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
1443 };
1444 RegisterHandlers(functions);
1445}
1446
1447ILibraryAppletCreator::~ILibraryAppletCreator() = default;
1448
1449void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
1450 IPC::RequestParser rp{ctx};
1451
1452 const auto applet_id = rp.PopRaw<Applets::AppletId>();
1453 const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>();
1454
1455 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
1456 applet_mode);
1457
1458 const auto& applet_manager{system.GetAppletManager()};
1459 const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
1460
1461 if (applet == nullptr) {
1462 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
1463
1464 IPC::ResponseBuilder rb{ctx, 2};
1465 rb.Push(ResultUnknown);
1466 return;
1467 }
1468
1469 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1470
1471 rb.Push(ResultSuccess);
1472 rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
1473}
1474
1475void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) {
1476 IPC::RequestParser rp{ctx};
1477
1478 const s64 size{rp.Pop<s64>()};
1479
1480 LOG_DEBUG(Service_AM, "called, size={}", size);
1481
1482 if (size <= 0) {
1483 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1484 IPC::ResponseBuilder rb{ctx, 2};
1485 rb.Push(ResultUnknown);
1486 return;
1487 }
1488
1489 std::vector<u8> buffer(size);
1490
1491 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1492 rb.Push(ResultSuccess);
1493 rb.PushIpcInterface<IStorage>(system, std::move(buffer));
1494}
1495
1496void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) {
1497 IPC::RequestParser rp{ctx};
1498
1499 struct Parameters {
1500 u8 permissions;
1501 s64 size;
1502 };
1503
1504 const auto parameters{rp.PopRaw<Parameters>()};
1505 const auto handle{ctx.GetCopyHandle(0)};
1506
1507 LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions,
1508 parameters.size, handle);
1509
1510 if (parameters.size <= 0) {
1511 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1512 IPC::ResponseBuilder rb{ctx, 2};
1513 rb.Push(ResultUnknown);
1514 return;
1515 }
1516
1517 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
1518
1519 if (transfer_mem.IsNull()) {
1520 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
1521 IPC::ResponseBuilder rb{ctx, 2};
1522 rb.Push(ResultUnknown);
1523 return;
1524 }
1525
1526 std::vector<u8> memory(transfer_mem->GetSize());
1527 ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
1528
1529 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1530 rb.Push(ResultSuccess);
1531 rb.PushIpcInterface<IStorage>(system, std::move(memory));
1532}
1533
1534void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
1535 IPC::RequestParser rp{ctx};
1536
1537 const s64 size{rp.Pop<s64>()};
1538 const auto handle{ctx.GetCopyHandle(0)};
1539
1540 LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
1541
1542 if (size <= 0) {
1543 LOG_ERROR(Service_AM, "size is less than or equal to 0");
1544 IPC::ResponseBuilder rb{ctx, 2};
1545 rb.Push(ResultUnknown);
1546 return;
1547 }
1548
1549 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
1550
1551 if (transfer_mem.IsNull()) {
1552 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
1553 IPC::ResponseBuilder rb{ctx, 2};
1554 rb.Push(ResultUnknown);
1555 return;
1556 }
1557
1558 std::vector<u8> memory(transfer_mem->GetSize());
1559 ctx.GetMemory().ReadBlock(transfer_mem->GetSourceAddress(), memory.data(), memory.size());
1560
1561 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1562 rb.Push(ResultSuccess);
1563 rb.PushIpcInterface<IStorage>(system, std::move(memory));
1564}
1565
1566ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_)
1567 : ServiceFramework{system_, "ILibraryAppletSelfAccessor"} {
1568 // clang-format off
1569 static const FunctionInfo functions[] = {
1570 {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"},
1571 {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"},
1572 {2, nullptr, "PopInteractiveInData"},
1573 {3, nullptr, "PushInteractiveOutData"},
1574 {5, nullptr, "GetPopInDataEvent"},
1575 {6, nullptr, "GetPopInteractiveInDataEvent"},
1576 {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
1577 {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
1578 {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
1579 {13, nullptr, "CanUseApplicationCore"},
1580 {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
1581 {15, nullptr, "GetMainAppletApplicationControlProperty"},
1582 {16, nullptr, "GetMainAppletStorageId"},
1583 {17, nullptr, "GetCallerAppletIdentityInfoStack"},
1584 {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
1585 {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"},
1586 {20, nullptr, "PopExtraStorage"},
1587 {25, nullptr, "GetPopExtraStorageEvent"},
1588 {30, nullptr, "UnpopInData"},
1589 {31, nullptr, "UnpopExtraStorage"},
1590 {40, nullptr, "GetIndirectLayerProducerHandle"},
1591 {50, nullptr, "ReportVisibleError"},
1592 {51, nullptr, "ReportVisibleErrorWithErrorContext"},
1593 {60, nullptr, "GetMainAppletApplicationDesiredLanguage"},
1594 {70, nullptr, "GetCurrentApplicationId"},
1595 {80, nullptr, "RequestExitToSelf"},
1596 {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
1597 {100, nullptr, "CreateGameMovieTrimmer"},
1598 {101, nullptr, "ReserveResourceForMovieOperation"},
1599 {102, nullptr, "UnreserveResourceForMovieOperation"},
1600 {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"},
1601 {120, nullptr, "GetLaunchStorageInfoForDebug"},
1602 {130, nullptr, "GetGpuErrorDetectedSystemEvent"},
1603 {140, nullptr, "SetApplicationMemoryReservation"},
1604 {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"},
1605 };
1606 // clang-format on
1607 RegisterHandlers(functions);
1608
1609 switch (system.GetAppletManager().GetCurrentAppletId()) {
1610 case Applets::AppletId::Cabinet:
1611 PushInShowCabinetData();
1612 break;
1613 case Applets::AppletId::MiiEdit:
1614 PushInShowMiiEditData();
1615 break;
1616 case Applets::AppletId::PhotoViewer:
1617 PushInShowAlbum();
1618 break;
1619 case Applets::AppletId::SoftwareKeyboard:
1620 PushInShowSoftwareKeyboard();
1621 break;
1622 case Applets::AppletId::Controller:
1623 PushInShowController();
1624 break;
1625 default:
1626 break;
1627 }
1628}
1629
1630ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
1631void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) {
1632 LOG_INFO(Service_AM, "called");
1633
1634 if (queue_data.empty()) {
1635 IPC::ResponseBuilder rb{ctx, 2};
1636 rb.Push(ResultNoDataInChannel);
1637 return;
1638 }
1639
1640 auto data = queue_data.front();
1641 queue_data.pop_front();
1642
1643 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
1644 rb.Push(ResultSuccess);
1645 rb.PushIpcInterface<IStorage>(system, std::move(data));
1646}
1647
1648void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) {
1649 LOG_WARNING(Service_AM, "(STUBBED) called");
1650
1651 IPC::ResponseBuilder rb{ctx, 2};
1652 rb.Push(ResultSuccess);
1653}
1654
1655void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) {
1656 LOG_WARNING(Service_AM, "(STUBBED) called");
1657
1658 system.Exit();
1659
1660 IPC::ResponseBuilder rb{ctx, 2};
1661 rb.Push(ResultSuccess);
1662}
1663
1664void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
1665 struct LibraryAppletInfo {
1666 Applets::AppletId applet_id;
1667 Applets::LibraryAppletMode library_applet_mode;
1668 };
1669
1670 LOG_WARNING(Service_AM, "(STUBBED) called");
1671
1672 const LibraryAppletInfo applet_info{
1673 .applet_id = system.GetAppletManager().GetCurrentAppletId(),
1674 .library_applet_mode = Applets::LibraryAppletMode::AllForeground,
1675 };
1676
1677 IPC::ResponseBuilder rb{ctx, 4};
1678 rb.Push(ResultSuccess);
1679 rb.PushRaw(applet_info);
1680}
1681
1682void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
1683 struct AppletIdentityInfo {
1684 Applets::AppletId applet_id;
1685 INSERT_PADDING_BYTES(0x4);
1686 u64 application_id;
1687 };
1688 static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
1689
1690 LOG_WARNING(Service_AM, "(STUBBED) called");
1691
1692 const AppletIdentityInfo applet_info{
1693 .applet_id = Applets::AppletId::QLaunch,
1694 .application_id = 0x0100000000001000ull,
1695 };
1696
1697 IPC::ResponseBuilder rb{ctx, 6};
1698 rb.Push(ResultSuccess);
1699 rb.PushRaw(applet_info);
1700}
1701
1702void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
1703 struct AppletIdentityInfo {
1704 Applets::AppletId applet_id;
1705 INSERT_PADDING_BYTES(0x4);
1706 u64 application_id;
1707 };
1708 static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
1709 LOG_WARNING(Service_AM, "(STUBBED) called");
1710
1711 const AppletIdentityInfo applet_info{
1712 .applet_id = Applets::AppletId::QLaunch,
1713 .application_id = 0x0100000000001000ull,
1714 };
1715
1716 IPC::ResponseBuilder rb{ctx, 6};
1717 rb.Push(ResultSuccess);
1718 rb.PushRaw(applet_info);
1719}
1720
1721void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) {
1722 LOG_WARNING(Service_AM, "(STUBBED) called");
1723
1724 IPC::ResponseBuilder rb{ctx, 3};
1725 rb.Push(ResultSuccess);
1726 rb.Push<u32>(0);
1727}
1728
1729void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) {
1730 const Service::Account::ProfileManager manager{};
1731 bool is_empty{true};
1732 s32 user_count{-1};
1733
1734 LOG_INFO(Service_AM, "called");
1735
1736 if (manager.GetUserCount() > 0) {
1737 is_empty = false;
1738 user_count = static_cast<s32>(manager.GetUserCount());
1739 ctx.WriteBuffer(manager.GetAllUsers());
1740 }
1741
1742 IPC::ResponseBuilder rb{ctx, 4};
1743 rb.Push(ResultSuccess);
1744 rb.Push<u8>(is_empty);
1745 rb.Push(user_count);
1746}
1747
1748void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) {
1749 LOG_WARNING(Service_AM, "(STUBBED) called");
1750
1751 IPC::ResponseBuilder rb{ctx, 2};
1752 rb.Push(ResultSuccess);
1753 rb.Push<u8>(0);
1754}
1755
1756void ILibraryAppletSelfAccessor::PushInShowAlbum() {
1757 const Applets::CommonArguments arguments{
1758 .arguments_version = Applets::CommonArgumentVersion::Version3,
1759 .size = Applets::CommonArgumentSize::Version3,
1760 .library_version = 1,
1761 .theme_color = Applets::ThemeColor::BasicBlack,
1762 .play_startup_sound = true,
1763 .system_tick = system.CoreTiming().GetClockTicks(),
1764 };
1765
1766 std::vector<u8> argument_data(sizeof(arguments));
1767 std::vector<u8> settings_data{2};
1768 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
1769 queue_data.emplace_back(std::move(argument_data));
1770 queue_data.emplace_back(std::move(settings_data));
1771}
1772
1773void ILibraryAppletSelfAccessor::PushInShowController() {
1774 const Applets::CommonArguments common_args = {
1775 .arguments_version = Applets::CommonArgumentVersion::Version3,
1776 .size = Applets::CommonArgumentSize::Version3,
1777 .library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8),
1778 .theme_color = Applets::ThemeColor::BasicBlack,
1779 .play_startup_sound = true,
1780 .system_tick = system.CoreTiming().GetClockTicks(),
1781 };
1782
1783 Applets::ControllerSupportArgNew user_args = {
1784 .header = {.player_count_min = 1,
1785 .player_count_max = 4,
1786 .enable_take_over_connection = true,
1787 .enable_left_justify = false,
1788 .enable_permit_joy_dual = true,
1789 .enable_single_mode = false,
1790 .enable_identification_color = false},
1791 .identification_colors = {},
1792 .enable_explain_text = false,
1793 .explain_text = {},
1794 };
1795
1796 Applets::ControllerSupportArgPrivate private_args = {
1797 .arg_private_size = sizeof(Applets::ControllerSupportArgPrivate),
1798 .arg_size = sizeof(Applets::ControllerSupportArgNew),
1799 .is_home_menu = true,
1800 .flag_1 = true,
1801 .mode = Applets::ControllerSupportMode::ShowControllerSupport,
1802 .caller = Applets::ControllerSupportCaller::
1803 Application, // switchbrew: Always zero except with
1804 // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
1805 // which sets this to the input param
1806 .style_set = Core::HID::NpadStyleSet::None,
1807 .joy_hold_type = 0,
1808 };
1809 std::vector<u8> common_args_data(sizeof(common_args));
1810 std::vector<u8> private_args_data(sizeof(private_args));
1811 std::vector<u8> user_args_data(sizeof(user_args));
1812
1813 std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
1814 std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
1815 std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
1816
1817 queue_data.emplace_back(std::move(common_args_data));
1818 queue_data.emplace_back(std::move(private_args_data));
1819 queue_data.emplace_back(std::move(user_args_data));
1820}
1821
1822void ILibraryAppletSelfAccessor::PushInShowCabinetData() {
1823 const Applets::CommonArguments arguments{
1824 .arguments_version = Applets::CommonArgumentVersion::Version3,
1825 .size = Applets::CommonArgumentSize::Version3,
1826 .library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1),
1827 .theme_color = Applets::ThemeColor::BasicBlack,
1828 .play_startup_sound = true,
1829 .system_tick = system.CoreTiming().GetClockTicks(),
1830 };
1831
1832 const Applets::StartParamForAmiiboSettings amiibo_settings{
1833 .param_1 = 0,
1834 .applet_mode = system.GetAppletManager().GetCabinetMode(),
1835 .flags = Applets::CabinetFlags::None,
1836 .amiibo_settings_1 = 0,
1837 .device_handle = 0,
1838 .tag_info{},
1839 .register_info{},
1840 .amiibo_settings_3{},
1841 };
1842
1843 std::vector<u8> argument_data(sizeof(arguments));
1844 std::vector<u8> settings_data(sizeof(amiibo_settings));
1845 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
1846 std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
1847 queue_data.emplace_back(std::move(argument_data));
1848 queue_data.emplace_back(std::move(settings_data));
1849}
1850
1851void ILibraryAppletSelfAccessor::PushInShowMiiEditData() {
1852 struct MiiEditV3 {
1853 Applets::MiiEditAppletInputCommon common;
1854 Applets::MiiEditAppletInputV3 input;
1855 };
1856 static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size.");
1857
1858 MiiEditV3 mii_arguments{
1859 .common =
1860 {
1861 .version = Applets::MiiEditAppletVersion::Version3,
1862 .applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit,
1863 },
1864 .input{},
1865 };
1866
1867 std::vector<u8> argument_data(sizeof(mii_arguments));
1868 std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments));
1869
1870 queue_data.emplace_back(std::move(argument_data));
1871}
1872
1873void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() {
1874 const Applets::CommonArguments arguments{
1875 .arguments_version = Applets::CommonArgumentVersion::Version3,
1876 .size = Applets::CommonArgumentSize::Version3,
1877 .library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301),
1878 .theme_color = Applets::ThemeColor::BasicBlack,
1879 .play_startup_sound = true,
1880 .system_tick = system.CoreTiming().GetClockTicks(),
1881 };
1882
1883 std::vector<char16_t> initial_string(0);
1884
1885 const Applets::SwkbdConfigCommon swkbd_config{
1886 .type = Applets::SwkbdType::Qwerty,
1887 .ok_text{},
1888 .left_optional_symbol_key{},
1889 .right_optional_symbol_key{},
1890 .use_prediction = false,
1891 .key_disable_flags{},
1892 .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start,
1893 .header_text{},
1894 .sub_text{},
1895 .guide_text{},
1896 .max_text_length = 500,
1897 .min_text_length = 0,
1898 .password_mode = Applets::SwkbdPasswordMode::Disabled,
1899 .text_draw_type = Applets::SwkbdTextDrawType::Box,
1900 .enable_return_button = true,
1901 .use_utf8 = false,
1902 .use_blur_background = true,
1903 .initial_string_offset{},
1904 .initial_string_length = static_cast<u32>(initial_string.size()),
1905 .user_dictionary_offset{},
1906 .user_dictionary_entries{},
1907 .use_text_check = false,
1908 };
1909
1910 Applets::SwkbdConfigNew swkbd_config_new{};
1911
1912 std::vector<u8> argument_data(sizeof(arguments));
1913 std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new));
1914 std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t));
1915
1916 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
1917 std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config));
1918 std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new,
1919 sizeof(Applets::SwkbdConfigNew));
1920 std::memcpy(work_buffer.data(), initial_string.data(),
1921 swkbd_config.initial_string_length * sizeof(char16_t));
1922
1923 queue_data.emplace_back(std::move(argument_data));
1924 queue_data.emplace_back(std::move(swkbd_data));
1925 queue_data.emplace_back(std::move(work_buffer));
1926}
1927
1928IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_)
1929 : ServiceFramework{system_, "IAppletCommonFunctions"} {
1930 // clang-format off
1931 static const FunctionInfo functions[] = {
1932 {0, nullptr, "SetTerminateResult"},
1933 {10, nullptr, "ReadThemeStorage"},
1934 {11, nullptr, "WriteThemeStorage"},
1935 {20, nullptr, "PushToAppletBoundChannel"},
1936 {21, nullptr, "TryPopFromAppletBoundChannel"},
1937 {40, nullptr, "GetDisplayLogicalResolution"},
1938 {42, nullptr, "SetDisplayMagnification"},
1939 {50, nullptr, "SetHomeButtonDoubleClickEnabled"},
1940 {51, nullptr, "GetHomeButtonDoubleClickEnabled"},
1941 {52, nullptr, "IsHomeButtonShortPressedBlocked"},
1942 {60, nullptr, "IsVrModeCurtainRequired"},
1943 {61, nullptr, "IsSleepRequiredByHighTemperature"},
1944 {62, nullptr, "IsSleepRequiredByLowBattery"},
1945 {70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"},
1946 {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
1947 {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
1948 {90, nullptr, "OpenNamedChannelAsParent"},
1949 {91, nullptr, "OpenNamedChannelAsChild"},
1950 {100, nullptr, "SetApplicationCoreUsageMode"},
1951 };
1952 // clang-format on
1953
1954 RegisterHandlers(functions);
1955}
1956
1957IAppletCommonFunctions::~IAppletCommonFunctions() = default;
1958
1959void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) {
1960 LOG_WARNING(Service_AM, "(STUBBED) called");
1961
1962 IPC::ResponseBuilder rb{ctx, 2};
1963 rb.Push(ResultSuccess);
1964}
1965
1966IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1967 : ServiceFramework{system_, "IApplicationFunctions"}, service_context{system,
1968 "IApplicationFunctions"} {
1969 // clang-format off
1970 static const FunctionInfo functions[] = {
1971 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
1972 {10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
1973 {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
1974 {12, nullptr, "CreateApplicationAndRequestToStart"},
1975 {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
1976 {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
1977 {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
1978 {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
1979 {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
1980 {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
1981 {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"},
1982 {24, nullptr, "GetLaunchStorageInfoForDebug"},
1983 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
1984 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
1985 {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
1986 {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"},
1987 {29, nullptr, "GetCacheStorageMax"},
1988 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
1989 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
1990 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
1991 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
1992 {34, nullptr, "SelectApplicationLicense"},
1993 {35, nullptr, "GetDeviceSaveDataSizeMax"},
1994 {36, nullptr, "GetLimitedApplicationLicense"},
1995 {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
1996 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
1997 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
1998 {60, nullptr, "SetMediaPlaybackStateForApplication"},
1999 {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"},
2000 {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
2001 {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"},
2002 {68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
2003 {70, nullptr, "RequestToShutdown"},
2004 {71, nullptr, "RequestToReboot"},
2005 {72, nullptr, "RequestToSleep"},
2006 {80, nullptr, "ExitAndRequestToShowThanksMessage"},
2007 {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
2008 {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"},
2009 {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"},
2010 {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
2011 {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
2012 {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
2013 {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
2014 {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
2015 {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
2016 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
2017 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
2018 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
2019 {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
2020 {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
2021 {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
2022 {150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"},
2023 {151, nullptr, "TryPopFromNotificationStorageChannel"},
2024 {160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"},
2025 {170, nullptr, "SetHdcpAuthenticationActivated"},
2026 {180, nullptr, "GetLaunchRequiredVersion"},
2027 {181, nullptr, "UpgradeLaunchRequiredVersion"},
2028 {190, nullptr, "SendServerMaintenanceOverlayNotification"},
2029 {200, nullptr, "GetLastApplicationExitReason"},
2030 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
2031 {1000, nullptr, "CreateMovieMaker"},
2032 {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
2033 };
2034 // clang-format on
2035
2036 RegisterHandlers(functions);
2037
2038 gpu_error_detected_event =
2039 service_context.CreateEvent("IApplicationFunctions:GpuErrorDetectedSystemEvent");
2040 friend_invitation_storage_channel_event =
2041 service_context.CreateEvent("IApplicationFunctions:FriendInvitationStorageChannelEvent");
2042 notification_storage_channel_event =
2043 service_context.CreateEvent("IApplicationFunctions:NotificationStorageChannelEvent");
2044 health_warning_disappeared_system_event =
2045 service_context.CreateEvent("IApplicationFunctions:HealthWarningDisappearedSystemEvent");
2046}
2047
2048IApplicationFunctions::~IApplicationFunctions() {
2049 service_context.CloseEvent(gpu_error_detected_event);
2050 service_context.CloseEvent(friend_invitation_storage_channel_event);
2051 service_context.CloseEvent(notification_storage_channel_event);
2052 service_context.CloseEvent(health_warning_disappeared_system_event);
2053}
2054
2055void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) {
2056 LOG_WARNING(Service_AM, "(STUBBED) called");
2057
2058 IPC::ResponseBuilder rb{ctx, 2};
2059 rb.Push(ResultSuccess);
2060}
2061
2062void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) {
2063 LOG_WARNING(Service_AM, "(STUBBED) called");
2064
2065 IPC::ResponseBuilder rb{ctx, 2};
2066 rb.Push(ResultSuccess);
2067}
2068
2069void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) {
2070 LOG_WARNING(Service_AM, "(STUBBED) called");
2071
2072 IPC::ResponseBuilder rb{ctx, 2};
2073 rb.Push(ResultSuccess);
2074}
2075
2076void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) {
2077 IPC::RequestParser rp{ctx};
2078 const auto is_visible = rp.Pop<bool>();
2079
2080 LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible);
2081
2082 IPC::ResponseBuilder rb{ctx, 2};
2083 rb.Push(ResultSuccess);
2084}
2085
2086void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
2087 LOG_WARNING(Service_AM, "(STUBBED) called");
2088
2089 IPC::ResponseBuilder rb{ctx, 2};
2090 rb.Push(ResultSuccess);
2091}
2092
2093void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
2094 LOG_WARNING(Service_AM, "(STUBBED) called");
2095
2096 IPC::ResponseBuilder rb{ctx, 2};
2097 rb.Push(ResultSuccess);
2098}
2099
2100void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) {
2101 LOG_WARNING(Service_AM, "(STUBBED) called");
2102
2103 IPC::ResponseBuilder rb{ctx, 2};
2104 rb.Push(ResultSuccess);
2105}
2106
2107void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) {
2108 LOG_WARNING(Service_AM, "(STUBBED) called");
2109
2110 IPC::ResponseBuilder rb{ctx, 2};
2111 rb.Push(ResultSuccess);
2112}
2113
2114void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
2115 IPC::RequestParser rp{ctx};
2116 const auto kind = rp.PopEnum<LaunchParameterKind>();
2117
2118 LOG_INFO(Service_AM, "called, kind={:08X}", kind);
2119
2120 if (kind == LaunchParameterKind::UserChannel) {
2121 auto channel = system.GetUserChannel();
2122 if (channel.empty()) {
2123 LOG_ERROR(Service_AM, "Attempted to load launch parameter but none was found!");
2124 IPC::ResponseBuilder rb{ctx, 2};
2125 rb.Push(AM::ResultNoDataInChannel);
2126 return;
2127 }
2128
2129 auto data = channel.back();
2130 channel.pop_back();
2131
2132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
2133 rb.Push(ResultSuccess);
2134 rb.PushIpcInterface<IStorage>(system, std::move(data));
2135 } else if (kind == LaunchParameterKind::AccountPreselectedUser &&
2136 !launch_popped_account_preselect) {
2137 // TODO: Verify this is hw-accurate
2138 LaunchParameterAccountPreselectedUser params{};
2139
2140 params.magic = LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC;
2141 params.is_account_selected = 1;
2142
2143 Account::ProfileManager profile_manager{};
2144 const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
2145 ASSERT(uuid.has_value() && uuid->IsValid());
2146 params.current_user = *uuid;
2147
2148 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
2149 rb.Push(ResultSuccess);
2150
2151 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
2152 std::memcpy(buffer.data(), &params, buffer.size());
2153
2154 rb.PushIpcInterface<IStorage>(system, std::move(buffer));
2155 launch_popped_account_preselect = true;
2156 } else {
2157 LOG_ERROR(Service_AM, "Unknown launch parameter kind.");
2158 IPC::ResponseBuilder rb{ctx, 2};
2159 rb.Push(AM::ResultNoDataInChannel);
2160 }
2161}
2162
2163void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
2164 LOG_WARNING(Service_AM, "(STUBBED) called");
2165
2166 IPC::ResponseBuilder rb{ctx, 2};
2167 rb.Push(ResultSuccess);
2168}
2169
2170void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
2171 IPC::RequestParser rp{ctx};
2172 u128 user_id = rp.PopRaw<u128>();
2173
2174 LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
2175
2176 FileSys::SaveDataAttribute attribute{};
2177 attribute.title_id = system.GetApplicationProcessProgramID();
2178 attribute.user_id = user_id;
2179 attribute.type = FileSys::SaveDataType::SaveData;
2180
2181 FileSys::VirtualDir save_data{};
2182 const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
2183 &save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
2184
2185 IPC::ResponseBuilder rb{ctx, 4};
2186 rb.Push(res);
2187 rb.Push<u64>(0);
2188}
2189
2190void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) {
2191 // Takes an input u32 Result, no output.
2192 // For example, in some cases official apps use this with error 0x2A2 then
2193 // uses svcBreak.
2194
2195 IPC::RequestParser rp{ctx};
2196 u32 result = rp.Pop<u32>();
2197 LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
2198
2199 IPC::ResponseBuilder rb{ctx, 2};
2200 rb.Push(ResultSuccess);
2201}
2202
2203void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) {
2204 LOG_DEBUG(Service_AM, "called");
2205
2206 std::array<u8, 0x10> version_string{};
2207
2208 const auto res = [this] {
2209 const auto title_id = system.GetApplicationProcessProgramID();
2210
2211 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
2212 system.GetContentProvider()};
2213 auto metadata = pm.GetControlMetadata();
2214 if (metadata.first != nullptr) {
2215 return metadata;
2216 }
2217
2218 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
2219 system.GetFileSystemController(),
2220 system.GetContentProvider()};
2221 return pm_update.GetControlMetadata();
2222 }();
2223
2224 if (res.first != nullptr) {
2225 const auto& version = res.first->GetVersionString();
2226 std::copy(version.begin(), version.end(), version_string.begin());
2227 } else {
2228 static constexpr char default_version[]{"1.0.0"};
2229 std::memcpy(version_string.data(), default_version, sizeof(default_version));
2230 }
2231
2232 IPC::ResponseBuilder rb{ctx, 6};
2233 rb.Push(ResultSuccess);
2234 rb.PushRaw(version_string);
2235}
2236
2237void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
2238 // TODO(bunnei): This should be configurable
2239 LOG_DEBUG(Service_AM, "called");
2240
2241 // Get supported languages from NACP, if possible
2242 // Default to 0 (all languages supported)
2243 u32 supported_languages = 0;
2244
2245 const auto res = [this] {
2246 const auto title_id = system.GetApplicationProcessProgramID();
2247
2248 const FileSys::PatchManager pm{title_id, system.GetFileSystemController(),
2249 system.GetContentProvider()};
2250 auto metadata = pm.GetControlMetadata();
2251 if (metadata.first != nullptr) {
2252 return metadata;
2253 }
2254
2255 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(title_id),
2256 system.GetFileSystemController(),
2257 system.GetContentProvider()};
2258 return pm_update.GetControlMetadata();
2259 }();
2260
2261 if (res.first != nullptr) {
2262 supported_languages = res.first->GetSupportedLanguages();
2263 }
2264
2265 // Call IApplicationManagerInterface implementation.
2266 auto& service_manager = system.ServiceManager();
2267 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
2268 auto app_man = ns_am2->GetApplicationManagerInterface();
2269
2270 // Get desired application language
2271 u8 desired_language{};
2272 const auto res_lang =
2273 app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
2274 if (res_lang != ResultSuccess) {
2275 IPC::ResponseBuilder rb{ctx, 2};
2276 rb.Push(res_lang);
2277 return;
2278 }
2279
2280 // Convert to settings language code.
2281 u64 language_code{};
2282 const auto res_code =
2283 app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
2284 if (res_code != ResultSuccess) {
2285 IPC::ResponseBuilder rb{ctx, 2};
2286 rb.Push(res_code);
2287 return;
2288 }
2289
2290 LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
2291
2292 IPC::ResponseBuilder rb{ctx, 4};
2293 rb.Push(ResultSuccess);
2294 rb.Push(language_code);
2295}
2296
2297void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {
2298 LOG_WARNING(Service_AM, "(STUBBED) called");
2299
2300 constexpr bool gameplay_recording_supported = false;
2301
2302 IPC::ResponseBuilder rb{ctx, 3};
2303 rb.Push(ResultSuccess);
2304 rb.Push(gameplay_recording_supported);
2305}
2306
2307void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) {
2308 LOG_WARNING(Service_AM, "(STUBBED) called");
2309
2310 IPC::ResponseBuilder rb{ctx, 2};
2311 rb.Push(ResultSuccess);
2312}
2313
2314void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) {
2315 LOG_WARNING(Service_AM, "(STUBBED) called");
2316
2317 IPC::ResponseBuilder rb{ctx, 2};
2318 rb.Push(ResultSuccess);
2319}
2320
2321void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) {
2322 LOG_WARNING(Service_AM, "(STUBBED) called");
2323
2324 IPC::ResponseBuilder rb{ctx, 3};
2325 rb.Push(ResultSuccess);
2326 rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
2327}
2328
2329void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) {
2330 LOG_WARNING(Service_AM, "(STUBBED) called");
2331
2332 IPC::ResponseBuilder rb{ctx, 6};
2333 rb.Push(ResultSuccess);
2334
2335 // Returns a 128-bit UUID
2336 rb.Push<u64>(0);
2337 rb.Push<u64>(0);
2338}
2339
2340void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) {
2341 struct Parameters {
2342 FileSys::SaveDataType type;
2343 u128 user_id;
2344 u64 new_normal_size;
2345 u64 new_journal_size;
2346 };
2347 static_assert(sizeof(Parameters) == 40);
2348
2349 IPC::RequestParser rp{ctx};
2350 const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>();
2351
2352 LOG_DEBUG(Service_AM,
2353 "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
2354 "new_journal={:016X}",
2355 static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
2356
2357 system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
2358 type, system.GetApplicationProcessProgramID(), user_id,
2359 {new_normal_size, new_journal_size});
2360
2361 IPC::ResponseBuilder rb{ctx, 4};
2362 rb.Push(ResultSuccess);
2363
2364 // The following value is used upon failure to help the system recover.
2365 // Since we always succeed, this should be 0.
2366 rb.Push<u64>(0);
2367}
2368
2369void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
2370 struct Parameters {
2371 FileSys::SaveDataType type;
2372 u128 user_id;
2373 };
2374 static_assert(sizeof(Parameters) == 24);
2375
2376 IPC::RequestParser rp{ctx};
2377 const auto [type, user_id] = rp.PopRaw<Parameters>();
2378
2379 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
2380 user_id[0]);
2381
2382 const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
2383 type, system.GetApplicationProcessProgramID(), user_id);
2384
2385 IPC::ResponseBuilder rb{ctx, 6};
2386 rb.Push(ResultSuccess);
2387 rb.Push(size.normal);
2388 rb.Push(size.journal);
2389}
2390
2391void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
2392 struct InputParameters {
2393 u16 index;
2394 s64 size;
2395 s64 journal_size;
2396 };
2397 static_assert(sizeof(InputParameters) == 24);
2398
2399 struct OutputParameters {
2400 u32 storage_target;
2401 u64 required_size;
2402 };
2403 static_assert(sizeof(OutputParameters) == 16);
2404
2405 IPC::RequestParser rp{ctx};
2406 const auto params = rp.PopRaw<InputParameters>();
2407
2408 LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
2409 params.index, params.size, params.journal_size);
2410
2411 const OutputParameters resp{
2412 .storage_target = 1,
2413 .required_size = 0,
2414 };
2415
2416 IPC::ResponseBuilder rb{ctx, 6};
2417 rb.Push(ResultSuccess);
2418 rb.PushRaw(resp);
2419}
2420
2421void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) {
2422 LOG_WARNING(Service_AM, "(STUBBED) called");
2423
2424 constexpr u64 size_max_normal = 0xFFFFFFF;
2425 constexpr u64 size_max_journal = 0xFFFFFFF;
2426
2427 IPC::ResponseBuilder rb{ctx, 6};
2428 rb.Push(ResultSuccess);
2429 rb.Push(size_max_normal);
2430 rb.Push(size_max_journal);
2431}
2432
2433void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
2434 LOG_WARNING(Service_AM, "(STUBBED) called");
2435
2436 IPC::ResponseBuilder rb{ctx, 3};
2437 rb.Push(ResultSuccess);
2438 rb.Push<u32>(0);
2439}
2440
2441void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) {
2442 LOG_WARNING(Service_AM, "(STUBBED) called");
2443
2444 IPC::ResponseBuilder rb{ctx, 3};
2445 rb.Push(ResultSuccess);
2446 rb.Push<u32>(0);
2447}
2448
2449void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
2450 LOG_WARNING(Service_AM, "(STUBBED) called");
2451
2452 IPC::RequestParser rp{ctx};
2453 [[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
2454 [[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
2455 const auto program_index = rp.Pop<u64>();
2456
2457 IPC::ResponseBuilder rb{ctx, 2};
2458 rb.Push(ResultSuccess);
2459
2460 system.ExecuteProgram(program_index);
2461}
2462
2463void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
2464 LOG_DEBUG(Service_AM, "called");
2465
2466 system.GetUserChannel().clear();
2467
2468 IPC::ResponseBuilder rb{ctx, 2};
2469 rb.Push(ResultSuccess);
2470}
2471
2472void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
2473 LOG_DEBUG(Service_AM, "called");
2474
2475 IPC::RequestParser rp{ctx};
2476 const auto storage = rp.PopIpcInterface<IStorage>().lock();
2477 if (storage) {
2478 system.GetUserChannel().push_back(storage->GetData());
2479 }
2480
2481 IPC::ResponseBuilder rb{ctx, 2};
2482 rb.Push(ResultSuccess);
2483}
2484
2485void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) {
2486 LOG_WARNING(Service_AM, "(STUBBED) called");
2487
2488 IPC::ResponseBuilder rb{ctx, 3};
2489 rb.Push(ResultSuccess);
2490 rb.Push<s32>(previous_program_index);
2491}
2492
2493void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) {
2494 LOG_WARNING(Service_AM, "(STUBBED) called");
2495
2496 IPC::ResponseBuilder rb{ctx, 2, 1};
2497 rb.Push(ResultSuccess);
2498 rb.PushCopyObjects(gpu_error_detected_event->GetReadableEvent());
2499}
2500
2501void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) {
2502 LOG_DEBUG(Service_AM, "called");
2503
2504 IPC::ResponseBuilder rb{ctx, 2, 1};
2505 rb.Push(ResultSuccess);
2506 rb.PushCopyObjects(friend_invitation_storage_channel_event->GetReadableEvent());
2507}
2508
2509void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
2510 LOG_DEBUG(Service_AM, "(STUBBED) called");
2511
2512 IPC::ResponseBuilder rb{ctx, 2};
2513 rb.Push(AM::ResultNoDataInChannel);
2514}
2515
2516void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) {
2517 LOG_DEBUG(Service_AM, "called");
2518
2519 IPC::ResponseBuilder rb{ctx, 2, 1};
2520 rb.Push(ResultSuccess);
2521 rb.PushCopyObjects(notification_storage_channel_event->GetReadableEvent());
2522}
2523
2524void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) {
2525 LOG_DEBUG(Service_AM, "called");
2526
2527 IPC::ResponseBuilder rb{ctx, 2, 1};
2528 rb.Push(ResultSuccess);
2529 rb.PushCopyObjects(health_warning_disappeared_system_event->GetReadableEvent());
2530}
2531
2532void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) {
2533 LOG_WARNING(Service_AM, "(STUBBED) called");
2534
2535 IPC::ResponseBuilder rb{ctx, 2};
2536 rb.Push(ResultSuccess);
2537}
2538
2539void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) { 14void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
2540 auto message_queue = std::make_shared<AppletMessageQueue>(system);
2541 auto server_manager = std::make_unique<ServerManager>(system); 15 auto server_manager = std::make_unique<ServerManager>(system);
2542 16
2543 server_manager->RegisterNamedService( 17 server_manager->RegisterNamedService("appletAE",
2544 "appletAE", std::make_shared<AppletAE>(nvnflinger, message_queue, system)); 18 std::make_shared<AppletAE>(nvnflinger, system));
2545 server_manager->RegisterNamedService( 19 server_manager->RegisterNamedService("appletOE",
2546 "appletOE", std::make_shared<AppletOE>(nvnflinger, message_queue, system)); 20 std::make_shared<AppletOE>(nvnflinger, system));
2547 server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system)); 21 server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system));
2548 server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system)); 22 server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system));
2549 server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(system)); 23 server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(system));
2550 ServerManager::RunServer(std::move(server_manager)); 24 ServerManager::RunServer(std::move(server_manager));
2551} 25}
2552 26
2553IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
2554 : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system,
2555 "IHomeMenuFunctions"} {
2556 // clang-format off
2557 static const FunctionInfo functions[] = {
2558 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
2559 {11, nullptr, "LockForeground"},
2560 {12, nullptr, "UnlockForeground"},
2561 {20, nullptr, "PopFromGeneralChannel"},
2562 {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
2563 {30, nullptr, "GetHomeButtonWriterLockAccessor"},
2564 {31, nullptr, "GetWriterLockAccessorEx"},
2565 {40, nullptr, "IsSleepEnabled"},
2566 {41, nullptr, "IsRebootEnabled"},
2567 {50, nullptr, "LaunchSystemApplet"},
2568 {51, nullptr, "LaunchStarter"},
2569 {100, nullptr, "PopRequestLaunchApplicationForDebug"},
2570 {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
2571 {200, nullptr, "LaunchDevMenu"},
2572 {1000, nullptr, "SetLastApplicationExitReason"},
2573 };
2574 // clang-format on
2575
2576 RegisterHandlers(functions);
2577
2578 pop_from_general_channel_event =
2579 service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent");
2580}
2581
2582IHomeMenuFunctions::~IHomeMenuFunctions() {
2583 service_context.CloseEvent(pop_from_general_channel_event);
2584}
2585
2586void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) {
2587 LOG_WARNING(Service_AM, "(STUBBED) called");
2588
2589 IPC::ResponseBuilder rb{ctx, 2};
2590 rb.Push(ResultSuccess);
2591}
2592
2593void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) {
2594 LOG_WARNING(Service_AM, "(STUBBED) called");
2595
2596 IPC::ResponseBuilder rb{ctx, 2, 1};
2597 rb.Push(ResultSuccess);
2598 rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
2599}
2600
2601IGlobalStateController::IGlobalStateController(Core::System& system_)
2602 : ServiceFramework{system_, "IGlobalStateController"} {
2603 // clang-format off
2604 static const FunctionInfo functions[] = {
2605 {0, nullptr, "RequestToEnterSleep"},
2606 {1, nullptr, "EnterSleep"},
2607 {2, nullptr, "StartSleepSequence"},
2608 {3, nullptr, "StartShutdownSequence"},
2609 {4, nullptr, "StartRebootSequence"},
2610 {9, nullptr, "IsAutoPowerDownRequested"},
2611 {10, nullptr, "LoadAndApplyIdlePolicySettings"},
2612 {11, nullptr, "NotifyCecSettingsChanged"},
2613 {12, nullptr, "SetDefaultHomeButtonLongPressTime"},
2614 {13, nullptr, "UpdateDefaultDisplayResolution"},
2615 {14, nullptr, "ShouldSleepOnBoot"},
2616 {15, nullptr, "GetHdcpAuthenticationFailedEvent"},
2617 {30, nullptr, "OpenCradleFirmwareUpdater"},
2618 };
2619 // clang-format on
2620
2621 RegisterHandlers(functions);
2622}
2623
2624IGlobalStateController::~IGlobalStateController() = default;
2625
2626IApplicationCreator::IApplicationCreator(Core::System& system_)
2627 : ServiceFramework{system_, "IApplicationCreator"} {
2628 // clang-format off
2629 static const FunctionInfo functions[] = {
2630 {0, nullptr, "CreateApplication"},
2631 {1, nullptr, "PopLaunchRequestedApplication"},
2632 {10, nullptr, "CreateSystemApplication"},
2633 {100, nullptr, "PopFloatingApplicationForDevelopment"},
2634 };
2635 // clang-format on
2636
2637 RegisterHandlers(functions);
2638}
2639
2640IApplicationCreator::~IApplicationCreator() = default;
2641
2642IProcessWindingController::IProcessWindingController(Core::System& system_)
2643 : ServiceFramework{system_, "IProcessWindingController"} {
2644 // clang-format off
2645 static const FunctionInfo functions[] = {
2646 {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"},
2647 {11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"},
2648 {21, nullptr, "PushContext"},
2649 {22, nullptr, "PopContext"},
2650 {23, nullptr, "CancelWindingReservation"},
2651 {30, nullptr, "WindAndDoReserved"},
2652 {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
2653 {41, nullptr, "ReserveToStartAndWait"},
2654 };
2655 // clang-format on
2656
2657 RegisterHandlers(functions);
2658}
2659
2660IProcessWindingController::~IProcessWindingController() = default;
2661
2662void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) {
2663 LOG_WARNING(Service_AM, "(STUBBED) called");
2664
2665 struct AppletProcessLaunchReason {
2666 u8 flag;
2667 INSERT_PADDING_BYTES(3);
2668 };
2669 static_assert(sizeof(AppletProcessLaunchReason) == 0x4,
2670 "AppletProcessLaunchReason is an invalid size");
2671
2672 AppletProcessLaunchReason reason{
2673 .flag = 0,
2674 };
2675
2676 IPC::ResponseBuilder rb{ctx, 3};
2677 rb.Push(ResultSuccess);
2678 rb.PushRaw(reason);
2679}
2680
2681void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
2682 const auto applet_id = system.GetAppletManager().GetCurrentAppletId();
2683 const auto applet_mode = Applets::LibraryAppletMode::AllForeground;
2684
2685 LOG_WARNING(Service_AM, "(STUBBED) called with applet_id={:08X}, applet_mode={:08X}", applet_id,
2686 applet_mode);
2687
2688 const auto& applet_manager{system.GetAppletManager()};
2689 const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
2690
2691 if (applet == nullptr) {
2692 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
2693
2694 IPC::ResponseBuilder rb{ctx, 2};
2695 rb.Push(ResultUnknown);
2696 return;
2697 }
2698
2699 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
2700 rb.Push(ResultSuccess);
2701 rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet);
2702}
2703
2704} // namespace Service::AM 27} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#pragma once 4#pragma once
5 5
6#include <chrono> 6namespace Core {
7#include <memory> 7class System;
8#include <queue> 8}
9
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/service.h"
12
13namespace Kernel {
14class KernelCore;
15class KReadableEvent;
16class KTransferMemory;
17} // namespace Kernel
18 9
19namespace Service::Nvnflinger { 10namespace Service::Nvnflinger {
20class Nvnflinger; 11class Nvnflinger;
@@ -22,443 +13,6 @@ class Nvnflinger;
22 13
23namespace Service::AM { 14namespace Service::AM {
24 15
25class AppletMessageQueue {
26public:
27 // This is nn::am::AppletMessage
28 enum class AppletMessage : u32 {
29 None = 0,
30 ChangeIntoForeground = 1,
31 ChangeIntoBackground = 2,
32 Exit = 4,
33 ApplicationExited = 6,
34 FocusStateChanged = 15,
35 Resume = 16,
36 DetectShortPressingHomeButton = 20,
37 DetectLongPressingHomeButton = 21,
38 DetectShortPressingPowerButton = 22,
39 DetectMiddlePressingPowerButton = 23,
40 DetectLongPressingPowerButton = 24,
41 RequestToPrepareSleep = 25,
42 FinishedSleepSequence = 26,
43 SleepRequiredByHighTemperature = 27,
44 SleepRequiredByLowBattery = 28,
45 AutoPowerDown = 29,
46 OperationModeChanged = 30,
47 PerformanceModeChanged = 31,
48 DetectReceivingCecSystemStandby = 32,
49 SdCardRemoved = 33,
50 LaunchApplicationRequested = 50,
51 RequestToDisplay = 51,
52 ShowApplicationLogo = 55,
53 HideApplicationLogo = 56,
54 ForceHideApplicationLogo = 57,
55 FloatingApplicationDetected = 60,
56 DetectShortPressingCaptureButton = 90,
57 AlbumScreenShotTaken = 92,
58 AlbumRecordingSaved = 93,
59 };
60
61 explicit AppletMessageQueue(Core::System& system);
62 ~AppletMessageQueue();
63
64 Kernel::KReadableEvent& GetMessageReceiveEvent();
65 Kernel::KReadableEvent& GetOperationModeChangedEvent();
66 void PushMessage(AppletMessage msg);
67 AppletMessage PopMessage();
68 std::size_t GetMessageCount() const;
69 void RequestExit();
70 void RequestResume();
71 void FocusStateChanged();
72 void OperationModeChanged();
73
74private:
75 KernelHelpers::ServiceContext service_context;
76
77 Kernel::KEvent* on_new_message;
78 Kernel::KEvent* on_operation_mode_changed;
79
80 std::queue<AppletMessage> messages;
81};
82
83class IWindowController final : public ServiceFramework<IWindowController> {
84public:
85 explicit IWindowController(Core::System& system_);
86 ~IWindowController() override;
87
88private:
89 void GetAppletResourceUserId(HLERequestContext& ctx);
90 void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
91 void AcquireForegroundRights(HLERequestContext& ctx);
92};
93
94class IAudioController final : public ServiceFramework<IAudioController> {
95public:
96 explicit IAudioController(Core::System& system_);
97 ~IAudioController() override;
98
99private:
100 void SetExpectedMasterVolume(HLERequestContext& ctx);
101 void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
102 void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
103 void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
104 void SetTransparentAudioRate(HLERequestContext& ctx);
105
106 static constexpr float min_allowed_volume = 0.0f;
107 static constexpr float max_allowed_volume = 1.0f;
108
109 float main_applet_volume{0.25f};
110 float library_applet_volume{max_allowed_volume};
111 float transparent_volume_rate{min_allowed_volume};
112
113 // Volume transition fade time in nanoseconds.
114 // e.g. If the main applet volume was 0% and was changed to 50%
115 // with a fade of 50ns, then over the course of 50ns,
116 // the volume will gradually fade up to 50%
117 std::chrono::nanoseconds fade_time_ns{0};
118};
119
120class IDisplayController final : public ServiceFramework<IDisplayController> {
121public:
122 explicit IDisplayController(Core::System& system_);
123 ~IDisplayController() override;
124
125private:
126 void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
127 void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
128 void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
129 void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
130 void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
131 void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
132};
133
134class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
135public:
136 explicit IDebugFunctions(Core::System& system_);
137 ~IDebugFunctions() override;
138};
139
140class ISelfController final : public ServiceFramework<ISelfController> {
141public:
142 explicit ISelfController(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger_);
143 ~ISelfController() override;
144
145private:
146 void Exit(HLERequestContext& ctx);
147 void LockExit(HLERequestContext& ctx);
148 void UnlockExit(HLERequestContext& ctx);
149 void EnterFatalSection(HLERequestContext& ctx);
150 void LeaveFatalSection(HLERequestContext& ctx);
151 void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
152 void SetScreenShotPermission(HLERequestContext& ctx);
153 void SetOperationModeChangedNotification(HLERequestContext& ctx);
154 void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
155 void SetFocusHandlingMode(HLERequestContext& ctx);
156 void SetRestartMessageEnabled(HLERequestContext& ctx);
157 void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
158 void SetAlbumImageOrientation(HLERequestContext& ctx);
159 void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
160 void GetSystemSharedBufferHandle(HLERequestContext& ctx);
161 void GetSystemSharedLayerHandle(HLERequestContext& ctx);
162 void CreateManagedDisplayLayer(HLERequestContext& ctx);
163 void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
164 void SetHandlesRequestToDisplay(HLERequestContext& ctx);
165 void ApproveToDisplay(HLERequestContext& ctx);
166 void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
167 void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
168 void ReportUserIsActive(HLERequestContext& ctx);
169 void SetAutoSleepDisabled(HLERequestContext& ctx);
170 void IsAutoSleepDisabled(HLERequestContext& ctx);
171 void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
172 void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
173 void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
174 void SaveCurrentScreenshot(HLERequestContext& ctx);
175 void SetRecordVolumeMuted(HLERequestContext& ctx);
176
177 Result EnsureBufferSharingEnabled();
178
179 enum class ScreenshotPermission : u32 {
180 Inherit = 0,
181 Enable = 1,
182 Disable = 2,
183 };
184
185 Nvnflinger::Nvnflinger& nvnflinger;
186
187 KernelHelpers::ServiceContext service_context;
188
189 Kernel::KEvent* launchable_event;
190 Kernel::KEvent* accumulated_suspended_tick_changed_event;
191
192 u32 idle_time_detection_extension = 0;
193 u64 num_fatal_sections_entered = 0;
194 u64 system_shared_buffer_id = 0;
195 u64 system_shared_layer_id = 0;
196 bool is_auto_sleep_disabled = false;
197 bool buffer_sharing_enabled = false;
198 ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
199};
200
201class ILockAccessor final : public ServiceFramework<ILockAccessor> {
202public:
203 explicit ILockAccessor(Core::System& system_);
204 ~ILockAccessor() override;
205
206private:
207 void TryLock(HLERequestContext& ctx);
208 void Unlock(HLERequestContext& ctx);
209 void GetEvent(HLERequestContext& ctx);
210 void IsLocked(HLERequestContext& ctx);
211
212 bool is_locked{};
213
214 Kernel::KEvent* lock_event;
215 KernelHelpers::ServiceContext service_context;
216};
217
218class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
219public:
220 explicit ICommonStateGetter(Core::System& system_,
221 std::shared_ptr<AppletMessageQueue> msg_queue_);
222 ~ICommonStateGetter() override;
223
224private:
225 // This is nn::oe::FocusState
226 enum class FocusState : u8 {
227 InFocus = 1,
228 NotInFocus = 2,
229 Background = 3,
230 };
231
232 // This is nn::oe::OperationMode
233 enum class OperationMode : u8 {
234 Handheld = 0,
235 Docked = 1,
236 };
237
238 // This is nn::am::service::SystemButtonType
239 enum class SystemButtonType {
240 None,
241 HomeButtonShortPressing,
242 HomeButtonLongPressing,
243 PowerButtonShortPressing,
244 PowerButtonLongPressing,
245 ShutdownSystem,
246 CaptureButtonShortPressing,
247 CaptureButtonLongPressing,
248 };
249
250 enum class SysPlatformRegion : s32 {
251 Global = 1,
252 Terra = 2,
253 };
254
255 void GetEventHandle(HLERequestContext& ctx);
256 void ReceiveMessage(HLERequestContext& ctx);
257 void GetCurrentFocusState(HLERequestContext& ctx);
258 void RequestToAcquireSleepLock(HLERequestContext& ctx);
259 void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
260 void GetReaderLockAccessorEx(HLERequestContext& ctx);
261 void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
262 void GetOperationMode(HLERequestContext& ctx);
263 void GetPerformanceMode(HLERequestContext& ctx);
264 void GetBootMode(HLERequestContext& ctx);
265 void IsVrModeEnabled(HLERequestContext& ctx);
266 void SetVrModeEnabled(HLERequestContext& ctx);
267 void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
268 void BeginVrModeEx(HLERequestContext& ctx);
269 void EndVrModeEx(HLERequestContext& ctx);
270 void GetDefaultDisplayResolution(HLERequestContext& ctx);
271 void SetCpuBoostMode(HLERequestContext& ctx);
272 void GetBuiltInDisplayType(HLERequestContext& ctx);
273 void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
274 void GetSettingsPlatformRegion(HLERequestContext& ctx);
275 void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
276
277 std::shared_ptr<AppletMessageQueue> msg_queue;
278 bool vr_mode_state{};
279 Kernel::KEvent* sleep_lock_event;
280 KernelHelpers::ServiceContext service_context;
281};
282
283class IStorageImpl {
284public:
285 virtual ~IStorageImpl();
286 virtual std::vector<u8>& GetData() = 0;
287 virtual const std::vector<u8>& GetData() const = 0;
288 virtual std::size_t GetSize() const = 0;
289};
290
291class IStorage final : public ServiceFramework<IStorage> {
292public:
293 explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
294 ~IStorage() override;
295
296 std::vector<u8>& GetData() {
297 return impl->GetData();
298 }
299
300 const std::vector<u8>& GetData() const {
301 return impl->GetData();
302 }
303
304 std::size_t GetSize() const {
305 return impl->GetSize();
306 }
307
308private:
309 void Register();
310 void Open(HLERequestContext& ctx);
311
312 std::shared_ptr<IStorageImpl> impl;
313};
314
315class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
316public:
317 explicit IStorageAccessor(Core::System& system_, IStorage& backing_);
318 ~IStorageAccessor() override;
319
320private:
321 void GetSize(HLERequestContext& ctx);
322 void Write(HLERequestContext& ctx);
323 void Read(HLERequestContext& ctx);
324
325 IStorage& backing;
326};
327
328class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
329public:
330 explicit ILibraryAppletCreator(Core::System& system_);
331 ~ILibraryAppletCreator() override;
332
333private:
334 void CreateLibraryApplet(HLERequestContext& ctx);
335 void CreateStorage(HLERequestContext& ctx);
336 void CreateTransferMemoryStorage(HLERequestContext& ctx);
337 void CreateHandleStorage(HLERequestContext& ctx);
338};
339
340class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
341public:
342 explicit ILibraryAppletSelfAccessor(Core::System& system_);
343 ~ILibraryAppletSelfAccessor() override;
344
345private:
346 void PopInData(HLERequestContext& ctx);
347 void PushOutData(HLERequestContext& ctx);
348 void GetLibraryAppletInfo(HLERequestContext& ctx);
349 void GetMainAppletIdentityInfo(HLERequestContext& ctx);
350 void ExitProcessAndReturn(HLERequestContext& ctx);
351 void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
352 void GetDesirableKeyboardLayout(HLERequestContext& ctx);
353 void GetMainAppletAvailableUsers(HLERequestContext& ctx);
354 void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx);
355
356 void PushInShowAlbum();
357 void PushInShowCabinetData();
358 void PushInShowMiiEditData();
359 void PushInShowSoftwareKeyboard();
360 void PushInShowController();
361
362 std::deque<std::vector<u8>> queue_data;
363};
364
365class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
366public:
367 explicit IAppletCommonFunctions(Core::System& system_);
368 ~IAppletCommonFunctions() override;
369
370private:
371 void SetCpuBoostRequestPriority(HLERequestContext& ctx);
372};
373
374class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
375public:
376 explicit IApplicationFunctions(Core::System& system_);
377 ~IApplicationFunctions() override;
378
379private:
380 void PopLaunchParameter(HLERequestContext& ctx);
381 void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
382 void EnsureSaveData(HLERequestContext& ctx);
383 void SetTerminateResult(HLERequestContext& ctx);
384 void GetDisplayVersion(HLERequestContext& ctx);
385 void GetDesiredLanguage(HLERequestContext& ctx);
386 void IsGamePlayRecordingSupported(HLERequestContext& ctx);
387 void InitializeGamePlayRecording(HLERequestContext& ctx);
388 void SetGamePlayRecordingState(HLERequestContext& ctx);
389 void NotifyRunning(HLERequestContext& ctx);
390 void GetPseudoDeviceId(HLERequestContext& ctx);
391 void ExtendSaveData(HLERequestContext& ctx);
392 void GetSaveDataSize(HLERequestContext& ctx);
393 void CreateCacheStorage(HLERequestContext& ctx);
394 void GetSaveDataSizeMax(HLERequestContext& ctx);
395 void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
396 void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
397 void BeginBlockingHomeButton(HLERequestContext& ctx);
398 void EndBlockingHomeButton(HLERequestContext& ctx);
399 void EnableApplicationCrashReport(HLERequestContext& ctx);
400 void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
401 void SetApplicationCopyrightImage(HLERequestContext& ctx);
402 void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
403 void QueryApplicationPlayStatistics(HLERequestContext& ctx);
404 void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
405 void ExecuteProgram(HLERequestContext& ctx);
406 void ClearUserChannel(HLERequestContext& ctx);
407 void UnpopToUserChannel(HLERequestContext& ctx);
408 void GetPreviousProgramIndex(HLERequestContext& ctx);
409 void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
410 void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
411 void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
412 void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
413 void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
414 void PrepareForJit(HLERequestContext& ctx);
415
416 KernelHelpers::ServiceContext service_context;
417
418 bool launch_popped_account_preselect = false;
419 s32 previous_program_index{-1};
420 Kernel::KEvent* gpu_error_detected_event;
421 Kernel::KEvent* friend_invitation_storage_channel_event;
422 Kernel::KEvent* notification_storage_channel_event;
423 Kernel::KEvent* health_warning_disappeared_system_event;
424};
425
426class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
427public:
428 explicit IHomeMenuFunctions(Core::System& system_);
429 ~IHomeMenuFunctions() override;
430
431private:
432 void RequestToGetForeground(HLERequestContext& ctx);
433 void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
434
435 KernelHelpers::ServiceContext service_context;
436
437 Kernel::KEvent* pop_from_general_channel_event;
438};
439
440class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
441public:
442 explicit IGlobalStateController(Core::System& system_);
443 ~IGlobalStateController() override;
444};
445
446class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
447public:
448 explicit IApplicationCreator(Core::System& system_);
449 ~IApplicationCreator() override;
450};
451
452class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
453public:
454 explicit IProcessWindingController(Core::System& system_);
455 ~IProcessWindingController() override;
456
457private:
458 void GetLaunchReason(HLERequestContext& ctx);
459 void OpenCallingLibraryApplet(HLERequestContext& ctx);
460};
461
462void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system); 16void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system);
463 17
464} // namespace Service::AM 18} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::AM {
9
10constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
11constexpr Result ResultNoMessages{ErrorModule::AM, 3};
12constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
13constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
14constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};
15
16} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Service::AM {
10
11namespace Frontend {
12class FrontendApplet;
13}
14
15enum class AppletType {
16 Application,
17 LibraryApplet,
18 SystemApplet,
19};
20
21enum class GameplayRecordingState : u32 {
22 Disabled,
23 Enabled,
24};
25
26// This is nn::oe::FocusState
27enum class FocusState : u8 {
28 InFocus = 1,
29 NotInFocus = 2,
30 Background = 3,
31};
32
33// This is nn::oe::OperationMode
34enum class OperationMode : u8 {
35 Handheld = 0,
36 Docked = 1,
37};
38
39// This is nn::am::service::SystemButtonType
40enum class SystemButtonType {
41 None,
42 HomeButtonShortPressing,
43 HomeButtonLongPressing,
44 PowerButtonShortPressing,
45 PowerButtonLongPressing,
46 ShutdownSystem,
47 CaptureButtonShortPressing,
48 CaptureButtonLongPressing,
49};
50
51enum class SysPlatformRegion : s32 {
52 Global = 1,
53 Terra = 2,
54};
55
56struct AppletProcessLaunchReason {
57 u8 flag;
58 INSERT_PADDING_BYTES(3);
59};
60static_assert(sizeof(AppletProcessLaunchReason) == 0x4,
61 "AppletProcessLaunchReason is an invalid size");
62
63enum class ScreenshotPermission : u32 {
64 Inherit = 0,
65 Enable = 1,
66 Disable = 2,
67};
68
69struct FocusHandlingMode {
70 bool unknown0;
71 bool unknown1;
72 bool unknown2;
73 bool unknown3;
74};
75
76enum class IdleTimeDetectionExtension : u32 {
77 Disabled = 0,
78 Extended = 1,
79 ExtendedUnsafe = 2,
80};
81
82enum class AppletId : u32 {
83 None = 0x00,
84 Application = 0x01,
85 OverlayDisplay = 0x02,
86 QLaunch = 0x03,
87 Starter = 0x04,
88 Auth = 0x0A,
89 Cabinet = 0x0B,
90 Controller = 0x0C,
91 DataErase = 0x0D,
92 Error = 0x0E,
93 NetConnect = 0x0F,
94 ProfileSelect = 0x10,
95 SoftwareKeyboard = 0x11,
96 MiiEdit = 0x12,
97 Web = 0x13,
98 Shop = 0x14,
99 PhotoViewer = 0x15,
100 Settings = 0x16,
101 OfflineWeb = 0x17,
102 LoginShare = 0x18,
103 WebAuth = 0x19,
104 MyPage = 0x1A,
105};
106
107enum class AppletProgramId : u64 {
108 QLaunch = 0x0100000000001000ull,
109 Auth = 0x0100000000001001ull,
110 Cabinet = 0x0100000000001002ull,
111 Controller = 0x0100000000001003ull,
112 DataErase = 0x0100000000001004ull,
113 Error = 0x0100000000001005ull,
114 NetConnect = 0x0100000000001006ull,
115 ProfileSelect = 0x0100000000001007ull,
116 SoftwareKeyboard = 0x0100000000001008ull,
117 MiiEdit = 0x0100000000001009ull,
118 Web = 0x010000000000100Aull,
119 Shop = 0x010000000000100Bull,
120 OverlayDisplay = 0x010000000000100Cull,
121 PhotoViewer = 0x010000000000100Dull,
122 Settings = 0x010000000000100Eull,
123 OfflineWeb = 0x010000000000100Full,
124 LoginShare = 0x0100000000001010ull,
125 WebAuth = 0x0100000000001011ull,
126 Starter = 0x0100000000001012ull,
127 MyPage = 0x0100000000001013ull,
128 MaxProgramId = 0x0100000000001FFFull,
129};
130
131enum class LibraryAppletMode : u32 {
132 AllForeground = 0,
133 Background = 1,
134 NoUI = 2,
135 BackgroundIndirectDisplay = 3,
136 AllForegroundInitiallyHidden = 4,
137};
138
139enum class CommonArgumentVersion : u32 {
140 Version0,
141 Version1,
142 Version2,
143 Version3,
144};
145
146enum class CommonArgumentSize : u32 {
147 Version3 = 0x20,
148};
149
150enum class ThemeColor : u32 {
151 BasicWhite = 0,
152 BasicBlack = 3,
153};
154
155struct CommonArguments {
156 CommonArgumentVersion arguments_version;
157 CommonArgumentSize size;
158 u32 library_version;
159 ThemeColor theme_color;
160 bool play_startup_sound;
161 u64 system_tick;
162};
163static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
164
165struct AppletIdentityInfo {
166 AppletId applet_id;
167 INSERT_PADDING_BYTES(0x4);
168 u64 application_id;
169};
170static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
171
172using AppletResourceUserId = u64;
173using ProgramId = u64;
174
175struct Applet;
176class AppletDataBroker;
177
178} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5
6#include "core/core.h"
7#include "core/hle/service/am/am_results.h"
8#include "core/hle/service/am/applet.h"
9#include "core/hle/service/am/applet_manager.h"
10
11namespace Service::AM {
12
13Applet::Applet(Core::System& system, std::unique_ptr<Process> process_)
14 : context(system, "Applet"), message_queue(system), process(std::move(process_)),
15 hid_registration(system, *process), gpu_error_detected_event(context),
16 friend_invitation_storage_channel_event(context), notification_storage_channel_event(context),
17 health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context),
18 pop_from_general_channel_event(context), library_applet_launchable_event(context),
19 accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) {
20
21 aruid = process->GetProcessId();
22 program_id = process->GetProgramId();
23}
24
25Applet::~Applet() = default;
26
27} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <list>
7#include <mutex>
8
9#include "common/math_util.h"
10#include "core/hle/service/apm/apm_controller.h"
11#include "core/hle/service/caps/caps_types.h"
12#include "core/hle/service/event.h"
13#include "core/hle/service/kernel_helpers.h"
14#include "core/hle/service/service.h"
15
16#include "core/hle/service/am/am_types.h"
17#include "core/hle/service/am/applet_message_queue.h"
18#include "core/hle/service/am/hid_registration.h"
19#include "core/hle/service/am/managed_layer_holder.h"
20#include "core/hle/service/am/process.h"
21#include "core/hle/service/am/storage.h"
22#include "core/hle/service/am/system_buffer_manager.h"
23
24namespace Service::AM {
25
26struct Applet {
27 explicit Applet(Core::System& system, std::unique_ptr<Process> process_);
28 ~Applet();
29
30 // Lock
31 std::mutex lock{};
32
33 // Event creation helper
34 KernelHelpers::ServiceContext context;
35
36 // Applet message queue
37 AppletMessageQueue message_queue;
38
39 // Process
40 std::unique_ptr<Process> process;
41
42 // Creation state
43 AppletId applet_id{};
44 AppletResourceUserId aruid{};
45 AppletProcessLaunchReason launch_reason{};
46 AppletType type{};
47 ProgramId program_id{};
48 LibraryAppletMode library_applet_mode{};
49 s32 previous_program_index{-1};
50 ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable};
51
52 // TODO: some fields above can be AppletIdentityInfo
53 AppletIdentityInfo screen_shot_identity;
54
55 // hid state
56 HidRegistration hid_registration;
57
58 // vi state
59 SystemBufferManager system_buffer_manager{};
60 ManagedLayerHolder managed_layer_holder{};
61
62 // Applet common functions
63 Result terminate_result{};
64 s32 display_logical_width{};
65 s32 display_logical_height{};
66 Common::Rectangle<f32> display_magnification{0, 0, 1, 1};
67 bool home_button_double_click_enabled{};
68 bool home_button_short_pressed_blocked{};
69 bool home_button_long_pressed_blocked{};
70 bool vr_mode_curtain_required{};
71 bool sleep_required_by_high_temperature{};
72 bool sleep_required_by_low_battery{};
73 s32 cpu_boost_request_priority{-1};
74 bool handling_capture_button_short_pressed_message_enabled_for_applet{};
75 bool handling_capture_button_long_pressed_message_enabled_for_applet{};
76 u32 application_core_usage_mode{};
77
78 // Application functions
79 bool gameplay_recording_supported{};
80 GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled};
81 bool jit_service_launched{};
82 bool is_running{};
83 bool application_crash_report_enabled{};
84
85 // Common state
86 FocusState focus_state{};
87 bool sleep_lock_enabled{};
88 bool vr_mode_enabled{};
89 bool lcd_backlight_off_enabled{};
90 APM::CpuBoostMode boost_mode{};
91 bool request_exit_to_library_applet_at_execute_next_program_enabled{};
92
93 // Channels
94 std::deque<std::vector<u8>> user_channel_launch_parameter{};
95 std::deque<std::vector<u8>> preselected_user_launch_parameter{};
96
97 // Caller applet
98 std::weak_ptr<Applet> caller_applet{};
99 std::shared_ptr<AppletDataBroker> caller_applet_broker{};
100
101 // Self state
102 bool exit_locked{};
103 s32 fatal_section_count{};
104 bool operation_mode_changed_notification_enabled{true};
105 bool performance_mode_changed_notification_enabled{true};
106 FocusHandlingMode focus_handling_mode{};
107 bool restart_message_enabled{};
108 bool out_of_focus_suspension_enabled{true};
109 Capture::AlbumImageOrientation album_image_orientation{};
110 bool handles_request_to_display{};
111 ScreenshotPermission screenshot_permission{};
112 IdleTimeDetectionExtension idle_time_detection_extension{};
113 bool auto_sleep_disabled{};
114 u64 suspended_ticks{};
115 bool album_image_taken_notification_enabled{};
116 bool record_volume_muted{};
117
118 // Events
119 Event gpu_error_detected_event;
120 Event friend_invitation_storage_channel_event;
121 Event notification_storage_channel_event;
122 Event health_warning_disappeared_system_event;
123 Event acquired_sleep_lock_event;
124 Event pop_from_general_channel_event;
125 Event library_applet_launchable_event;
126 Event accumulated_suspended_tick_changed_event;
127 Event sleep_lock_event;
128
129 // Frontend state
130 std::shared_ptr<Frontend::FrontendApplet> frontend{};
131};
132
133} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h"
5#include "core/core.h"
6#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/applet_ae.h" 4#include "core/hle/service/am/applet_ae.h"
5#include "core/hle/service/am/applet_manager.h"
6#include "core/hle/service/am/library_applet_proxy.h"
7#include "core/hle/service/am/system_applet_proxy.h"
8#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nvnflinger/nvnflinger.h"
10 9
11namespace Service::AM { 10namespace Service::AM {
12 11
13class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> { 12AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
14public: 13 : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_} {
15 explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_, 14 // clang-format off
16 std::shared_ptr<AppletMessageQueue> msg_queue_, 15 static const FunctionInfo functions[] = {
17 Core::System& system_) 16 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
18 : ServiceFramework{system_, "ILibraryAppletProxy"}, 17 {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"},
19 nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { 18 {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"},
20 // clang-format off 19 {300, nullptr, "OpenOverlayAppletProxy"},
21 static const FunctionInfo functions[] = { 20 {350, nullptr, "OpenSystemApplicationProxy"},
22 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 21 {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
23 {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"}, 22 {410, nullptr, "GetSystemAppletControllerForDebug"},
24 {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"}, 23 {1000, nullptr, "GetDebugFunctions"},
25 {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"}, 24 };
26 {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"}, 25 // clang-format on
27 {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
28 {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
29 {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
30 {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
31 {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
32 {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
33 {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
34 };
35 // clang-format on
36
37 RegisterHandlers(functions);
38 }
39
40private:
41 void GetCommonStateGetter(HLERequestContext& ctx) {
42 LOG_DEBUG(Service_AM, "called");
43
44 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
45 rb.Push(ResultSuccess);
46 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
47 }
48
49 void GetSelfController(HLERequestContext& ctx) {
50 LOG_DEBUG(Service_AM, "called");
51
52 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
53 rb.Push(ResultSuccess);
54 rb.PushIpcInterface<ISelfController>(system, nvnflinger);
55 }
56
57 void GetWindowController(HLERequestContext& ctx) {
58 LOG_DEBUG(Service_AM, "called");
59
60 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
61 rb.Push(ResultSuccess);
62 rb.PushIpcInterface<IWindowController>(system);
63 }
64
65 void GetAudioController(HLERequestContext& ctx) {
66 LOG_DEBUG(Service_AM, "called");
67
68 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
69 rb.Push(ResultSuccess);
70 rb.PushIpcInterface<IAudioController>(system);
71 }
72
73 void GetDisplayController(HLERequestContext& ctx) {
74 LOG_DEBUG(Service_AM, "called");
75
76 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
77 rb.Push(ResultSuccess);
78 rb.PushIpcInterface<IDisplayController>(system);
79 }
80
81 void GetProcessWindingController(HLERequestContext& ctx) {
82 LOG_DEBUG(Service_AM, "called");
83
84 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
85 rb.Push(ResultSuccess);
86 rb.PushIpcInterface<IProcessWindingController>(system);
87 }
88
89 void GetLibraryAppletCreator(HLERequestContext& ctx) {
90 LOG_DEBUG(Service_AM, "called");
91
92 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
93 rb.Push(ResultSuccess);
94 rb.PushIpcInterface<ILibraryAppletCreator>(system);
95 }
96
97 void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
98 LOG_DEBUG(Service_AM, "called");
99
100 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
101 rb.Push(ResultSuccess);
102 rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system);
103 }
104
105 void GetAppletCommonFunctions(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_AM, "called");
107
108 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
109 rb.Push(ResultSuccess);
110 rb.PushIpcInterface<IAppletCommonFunctions>(system);
111 }
112
113 void GetHomeMenuFunctions(HLERequestContext& ctx) {
114 LOG_DEBUG(Service_AM, "called");
115
116 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
117 rb.Push(ResultSuccess);
118 rb.PushIpcInterface<IHomeMenuFunctions>(system);
119 }
120
121 void GetGlobalStateController(HLERequestContext& ctx) {
122 LOG_DEBUG(Service_AM, "called");
123
124 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
125 rb.Push(ResultSuccess);
126 rb.PushIpcInterface<IGlobalStateController>(system);
127 }
128
129 void GetDebugFunctions(HLERequestContext& ctx) {
130 LOG_DEBUG(Service_AM, "called");
131
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(ResultSuccess);
134 rb.PushIpcInterface<IDebugFunctions>(system);
135 }
136
137 Nvnflinger::Nvnflinger& nvnflinger;
138 std::shared_ptr<AppletMessageQueue> msg_queue;
139};
140
141class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
142public:
143 explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
144 std::shared_ptr<AppletMessageQueue> msg_queue_,
145 Core::System& system_)
146 : ServiceFramework{system_, "ISystemAppletProxy"},
147 nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} {
148 // clang-format off
149 static const FunctionInfo functions[] = {
150 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
151 {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
152 {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"},
153 {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"},
154 {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"},
155 {10, nullptr, "GetProcessWindingController"},
156 {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
157 {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
158 {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
159 {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"},
160 {23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
161 {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
162 };
163 // clang-format on
164
165 RegisterHandlers(functions);
166 }
167
168private:
169 void GetCommonStateGetter(HLERequestContext& ctx) {
170 LOG_DEBUG(Service_AM, "called");
171
172 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
173 rb.Push(ResultSuccess);
174 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
175 }
176
177 void GetSelfController(HLERequestContext& ctx) {
178 LOG_DEBUG(Service_AM, "called");
179
180 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
181 rb.Push(ResultSuccess);
182 rb.PushIpcInterface<ISelfController>(system, nvnflinger);
183 }
184
185 void GetWindowController(HLERequestContext& ctx) {
186 LOG_DEBUG(Service_AM, "called");
187
188 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
189 rb.Push(ResultSuccess);
190 rb.PushIpcInterface<IWindowController>(system);
191 }
192
193 void GetAudioController(HLERequestContext& ctx) {
194 LOG_DEBUG(Service_AM, "called");
195
196 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
197 rb.Push(ResultSuccess);
198 rb.PushIpcInterface<IAudioController>(system);
199 }
200
201 void GetDisplayController(HLERequestContext& ctx) {
202 LOG_DEBUG(Service_AM, "called");
203
204 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
205 rb.Push(ResultSuccess);
206 rb.PushIpcInterface<IDisplayController>(system);
207 }
208 26
209 void GetLibraryAppletCreator(HLERequestContext& ctx) { 27 RegisterHandlers(functions);
210 LOG_DEBUG(Service_AM, "called"); 28}
211 29
212 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 30AppletAE::~AppletAE() = default;
213 rb.Push(ResultSuccess);
214 rb.PushIpcInterface<ILibraryAppletCreator>(system);
215 }
216 31
217 void GetHomeMenuFunctions(HLERequestContext& ctx) { 32void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
218 LOG_DEBUG(Service_AM, "called"); 33 LOG_DEBUG(Service_AM, "called");
219 34
35 if (const auto applet = GetAppletFromContext(ctx)) {
220 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 36 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
221 rb.Push(ResultSuccess); 37 rb.Push(ResultSuccess);
222 rb.PushIpcInterface<IHomeMenuFunctions>(system); 38 rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, applet, system);
223 } 39 } else {
224 40 UNIMPLEMENTED();
225 void GetGlobalStateController(HLERequestContext& ctx) {
226 LOG_DEBUG(Service_AM, "called");
227 41
228 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 42 IPC::ResponseBuilder rb{ctx, 2};
229 rb.Push(ResultSuccess); 43 rb.Push(ResultUnknown);
230 rb.PushIpcInterface<IGlobalStateController>(system);
231 }
232
233 void GetApplicationCreator(HLERequestContext& ctx) {
234 LOG_DEBUG(Service_AM, "called");
235
236 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
237 rb.Push(ResultSuccess);
238 rb.PushIpcInterface<IApplicationCreator>(system);
239 } 44 }
45}
240 46
241 void GetAppletCommonFunctions(HLERequestContext& ctx) { 47void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
242 LOG_DEBUG(Service_AM, "called"); 48 LOG_DEBUG(Service_AM, "called");
243 49
50 if (const auto applet = GetAppletFromContext(ctx)) {
244 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 51 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
245 rb.Push(ResultSuccess); 52 rb.Push(ResultSuccess);
246 rb.PushIpcInterface<IAppletCommonFunctions>(system); 53 rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, applet, system);
247 } 54 } else {
248 55 UNIMPLEMENTED();
249 void GetDebugFunctions(HLERequestContext& ctx) {
250 LOG_DEBUG(Service_AM, "called");
251 56
252 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 57 IPC::ResponseBuilder rb{ctx, 2};
253 rb.Push(ResultSuccess); 58 rb.Push(ResultUnknown);
254 rb.PushIpcInterface<IDebugFunctions>(system);
255 } 59 }
256
257 Nvnflinger::Nvnflinger& nvnflinger;
258 std::shared_ptr<AppletMessageQueue> msg_queue;
259};
260
261void AppletAE::OpenSystemAppletProxy(HLERequestContext& ctx) {
262 LOG_DEBUG(Service_AM, "called");
263
264 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
265 rb.Push(ResultSuccess);
266 rb.PushIpcInterface<ISystemAppletProxy>(nvnflinger, msg_queue, system);
267}
268
269void AppletAE::OpenLibraryAppletProxy(HLERequestContext& ctx) {
270 LOG_DEBUG(Service_AM, "called");
271
272 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
273 rb.Push(ResultSuccess);
274 rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
275} 60}
276 61
277void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) { 62void AppletAE::OpenLibraryAppletProxyOld(HLERequestContext& ctx) {
278 LOG_DEBUG(Service_AM, "called"); 63 LOG_DEBUG(Service_AM, "called");
279 64
280 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 65 return OpenLibraryAppletProxy(ctx);
281 rb.Push(ResultSuccess);
282 rb.PushIpcInterface<ILibraryAppletProxy>(nvnflinger, msg_queue, system);
283} 66}
284 67
285AppletAE::AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, 68std::shared_ptr<Applet> AppletAE::GetAppletFromContext(HLERequestContext& ctx) {
286 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_) 69 const auto aruid = ctx.GetPID();
287 : ServiceFramework{system_, "appletAE"}, nvnflinger{nvnflinger_}, msg_queue{ 70 return system.GetAppletManager().GetByAppletResourceUserId(aruid);
288 std::move(msg_queue_)} {
289 // clang-format off
290 static const FunctionInfo functions[] = {
291 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
292 {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"},
293 {201, &AppletAE::OpenLibraryAppletProxy, "OpenLibraryAppletProxy"},
294 {300, nullptr, "OpenOverlayAppletProxy"},
295 {350, nullptr, "OpenSystemApplicationProxy"},
296 {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
297 {410, nullptr, "GetSystemAppletControllerForDebug"},
298 {1000, nullptr, "GetDebugFunctions"},
299 };
300 // clang-format on
301
302 RegisterHandlers(functions);
303}
304
305AppletAE::~AppletAE() = default;
306
307const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
308 return msg_queue;
309} 71}
310 72
311} // namespace Service::AM 73} // 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;
18 18
19namespace AM { 19namespace AM {
20 20
21class AppletMessageQueue; 21struct Applet;
22 22
23class AppletAE final : public ServiceFramework<AppletAE> { 23class AppletAE final : public ServiceFramework<AppletAE> {
24public: 24public:
25 explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, 25 explicit AppletAE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_);
26 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
27 ~AppletAE() override; 26 ~AppletAE() override;
28 27
29 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
30
31private: 28private:
32 void OpenSystemAppletProxy(HLERequestContext& ctx); 29 void OpenSystemAppletProxy(HLERequestContext& ctx);
33 void OpenLibraryAppletProxy(HLERequestContext& ctx); 30 void OpenLibraryAppletProxy(HLERequestContext& ctx);
34 void OpenLibraryAppletProxyOld(HLERequestContext& ctx); 31 void OpenLibraryAppletProxyOld(HLERequestContext& ctx);
35 32
33 std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);
34
36 Nvnflinger::Nvnflinger& nvnflinger; 35 Nvnflinger::Nvnflinger& nvnflinger;
37 std::shared_ptr<AppletMessageQueue> msg_queue;
38}; 36};
39 37
40} // namespace AM 38} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet.h"
5#include "core/hle/service/am/applet_common_functions.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::AM {
9
10IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
11 std::shared_ptr<Applet> applet_)
12 : ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} {
13 // clang-format off
14 static const FunctionInfo functions[] = {
15 {0, nullptr, "SetTerminateResult"},
16 {10, nullptr, "ReadThemeStorage"},
17 {11, nullptr, "WriteThemeStorage"},
18 {20, nullptr, "PushToAppletBoundChannel"},
19 {21, nullptr, "TryPopFromAppletBoundChannel"},
20 {40, nullptr, "GetDisplayLogicalResolution"},
21 {42, nullptr, "SetDisplayMagnification"},
22 {50, nullptr, "SetHomeButtonDoubleClickEnabled"},
23 {51, nullptr, "GetHomeButtonDoubleClickEnabled"},
24 {52, nullptr, "IsHomeButtonShortPressedBlocked"},
25 {60, nullptr, "IsVrModeCurtainRequired"},
26 {61, nullptr, "IsSleepRequiredByHighTemperature"},
27 {62, nullptr, "IsSleepRequiredByLowBattery"},
28 {70, &IAppletCommonFunctions::SetCpuBoostRequestPriority, "SetCpuBoostRequestPriority"},
29 {80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
30 {81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
31 {90, nullptr, "OpenNamedChannelAsParent"},
32 {91, nullptr, "OpenNamedChannelAsChild"},
33 {100, nullptr, "SetApplicationCoreUsageMode"},
34 {300, &IAppletCommonFunctions::GetCurrentApplicationId, "GetCurrentApplicationId"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39}
40
41IAppletCommonFunctions::~IAppletCommonFunctions() = default;
42
43void IAppletCommonFunctions::SetCpuBoostRequestPriority(HLERequestContext& ctx) {
44 LOG_WARNING(Service_AM, "(STUBBED) called");
45
46 IPC::RequestParser rp{ctx};
47
48 std::scoped_lock lk{applet->lock};
49 applet->cpu_boost_request_priority = rp.Pop<s32>();
50
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(ResultSuccess);
53}
54
55void IAppletCommonFunctions::GetCurrentApplicationId(HLERequestContext& ctx) {
56 LOG_WARNING(Service_AM, "(STUBBED) called");
57
58 IPC::ResponseBuilder rb{ctx, 4};
59 rb.Push(ResultSuccess);
60 rb.Push<u64>(system.GetApplicationProcessProgramID() & ~0xFFFULL);
61}
62
63} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
13public:
14 explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~IAppletCommonFunctions() override;
16
17private:
18 void SetCpuBoostRequestPriority(HLERequestContext& ctx);
19 void GetCurrentApplicationId(HLERequestContext& ctx);
20
21 const std::shared_ptr<Applet> applet;
22};
23
24} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5
6#include "core/core.h"
7#include "core/hle/service/am/am_results.h"
8#include "core/hle/service/am/applet_data_broker.h"
9#include "core/hle/service/am/applet_manager.h"
10
11namespace Service::AM {
12
13AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context)
14 : m_event(context) {}
15AppletStorageChannel::~AppletStorageChannel() = default;
16
17void AppletStorageChannel::Push(std::shared_ptr<IStorage> storage) {
18 std::scoped_lock lk{m_lock};
19
20 m_data.emplace_back(std::move(storage));
21 m_event.Signal();
22}
23
24Result AppletStorageChannel::Pop(std::shared_ptr<IStorage>* out_storage) {
25 std::scoped_lock lk{m_lock};
26
27 SCOPE_EXIT({
28 if (m_data.empty()) {
29 m_event.Clear();
30 }
31 });
32
33 R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel);
34
35 *out_storage = std::move(m_data.front());
36 m_data.pop_front();
37
38 R_SUCCEED();
39}
40
41Kernel::KReadableEvent* AppletStorageChannel::GetEvent() {
42 return m_event.GetHandle();
43}
44
45AppletDataBroker::AppletDataBroker(Core::System& system_)
46 : system(system_), context(system_, "AppletDataBroker"), in_data(context),
47 interactive_in_data(context), out_data(context), interactive_out_data(context),
48 state_changed_event(context), is_completed(false) {}
49
50AppletDataBroker::~AppletDataBroker() = default;
51
52void AppletDataBroker::SignalCompletion() {
53 {
54 std::scoped_lock lk{lock};
55
56 if (is_completed) {
57 return;
58 }
59
60 is_completed = true;
61 state_changed_event.Signal();
62 }
63
64 system.GetAppletManager().FocusStateChanged();
65}
66
67} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <deque>
7#include <memory>
8#include <mutex>
9
10#include "core/hle/service/event.h"
11#include "core/hle/service/kernel_helpers.h"
12
13union Result;
14
15namespace Service::AM {
16
17struct Applet;
18class IStorage;
19
20class AppletStorageChannel {
21public:
22 explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx);
23 ~AppletStorageChannel();
24
25 void Push(std::shared_ptr<IStorage> storage);
26 Result Pop(std::shared_ptr<IStorage>* out_storage);
27 Kernel::KReadableEvent* GetEvent();
28
29private:
30 std::mutex m_lock{};
31 std::deque<std::shared_ptr<IStorage>> m_data{};
32 Event m_event;
33};
34
35class AppletDataBroker {
36public:
37 explicit AppletDataBroker(Core::System& system_);
38 ~AppletDataBroker();
39
40 AppletStorageChannel& GetInData() {
41 return in_data;
42 }
43
44 AppletStorageChannel& GetInteractiveInData() {
45 return interactive_in_data;
46 }
47
48 AppletStorageChannel& GetOutData() {
49 return out_data;
50 }
51
52 AppletStorageChannel& GetInteractiveOutData() {
53 return interactive_out_data;
54 }
55
56 Event& GetStateChangedEvent() {
57 return state_changed_event;
58 }
59
60 bool IsCompleted() const {
61 return is_completed;
62 }
63
64 void SignalCompletion();
65
66private:
67 Core::System& system;
68 KernelHelpers::ServiceContext context;
69
70 AppletStorageChannel in_data;
71 AppletStorageChannel interactive_in_data;
72 AppletStorageChannel out_data;
73 AppletStorageChannel interactive_out_data;
74 Event state_changed_event;
75
76 std::mutex lock;
77 bool is_completed;
78};
79
80} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "common/uuid.h"
6#include "core/core.h"
7#include "core/core_timing.h"
8#include "core/hle/service/acc/profile_manager.h"
9#include "core/hle/service/am/applet_data_broker.h"
10#include "core/hle/service/am/applet_manager.h"
11#include "core/hle/service/am/frontend/applet_cabinet.h"
12#include "core/hle/service/am/frontend/applet_controller.h"
13#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
14#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
15#include "hid_core/hid_types.h"
16
17namespace Service::AM {
18
19namespace {
20
21constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA;
22
23struct LaunchParameterAccountPreselectedUser {
24 u32 magic;
25 u32 is_account_selected;
26 Common::UUID current_user;
27 INSERT_PADDING_BYTES(0x70);
28};
29static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88);
30
31AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system,
32 std::shared_ptr<Applet>& applet) {
33 applet->caller_applet_broker = std::make_shared<AppletDataBroker>(system);
34 return applet->caller_applet_broker->GetInData();
35}
36
37void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) {
38 const CommonArguments arguments{
39 .arguments_version = CommonArgumentVersion::Version3,
40 .size = CommonArgumentSize::Version3,
41 .library_version = 1,
42 .theme_color = ThemeColor::BasicBlack,
43 .play_startup_sound = true,
44 .system_tick = system.CoreTiming().GetClockTicks(),
45 };
46
47 std::vector<u8> argument_data(sizeof(arguments));
48 std::vector<u8> settings_data{2};
49 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
50 channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
51 channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
52}
53
54void PushInShowController(Core::System& system, AppletStorageChannel& channel) {
55 const CommonArguments common_args = {
56 .arguments_version = CommonArgumentVersion::Version3,
57 .size = CommonArgumentSize::Version3,
58 .library_version = static_cast<u32>(Frontend::ControllerAppletVersion::Version8),
59 .theme_color = ThemeColor::BasicBlack,
60 .play_startup_sound = true,
61 .system_tick = system.CoreTiming().GetClockTicks(),
62 };
63
64 Frontend::ControllerSupportArgNew user_args = {
65 .header = {.player_count_min = 1,
66 .player_count_max = 4,
67 .enable_take_over_connection = true,
68 .enable_left_justify = false,
69 .enable_permit_joy_dual = true,
70 .enable_single_mode = false,
71 .enable_identification_color = false},
72 .identification_colors = {},
73 .enable_explain_text = false,
74 .explain_text = {},
75 };
76
77 Frontend::ControllerSupportArgPrivate private_args = {
78 .arg_private_size = sizeof(Frontend::ControllerSupportArgPrivate),
79 .arg_size = sizeof(Frontend::ControllerSupportArgNew),
80 .is_home_menu = true,
81 .flag_1 = true,
82 .mode = Frontend::ControllerSupportMode::ShowControllerSupport,
83 .caller = Frontend::ControllerSupportCaller::
84 Application, // switchbrew: Always zero except with
85 // ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
86 // which sets this to the input param
87 .style_set = Core::HID::NpadStyleSet::None,
88 .joy_hold_type = 0,
89 };
90 std::vector<u8> common_args_data(sizeof(common_args));
91 std::vector<u8> private_args_data(sizeof(private_args));
92 std::vector<u8> user_args_data(sizeof(user_args));
93
94 std::memcpy(common_args_data.data(), &common_args, sizeof(common_args));
95 std::memcpy(private_args_data.data(), &private_args, sizeof(private_args));
96 std::memcpy(user_args_data.data(), &user_args, sizeof(user_args));
97
98 channel.Push(std::make_shared<IStorage>(system, std::move(common_args_data)));
99 channel.Push(std::make_shared<IStorage>(system, std::move(private_args_data)));
100 channel.Push(std::make_shared<IStorage>(system, std::move(user_args_data)));
101}
102
103void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) {
104 const CommonArguments arguments{
105 .arguments_version = CommonArgumentVersion::Version3,
106 .size = CommonArgumentSize::Version3,
107 .library_version = static_cast<u32>(Frontend::CabinetAppletVersion::Version1),
108 .theme_color = ThemeColor::BasicBlack,
109 .play_startup_sound = true,
110 .system_tick = system.CoreTiming().GetClockTicks(),
111 };
112
113 const Frontend::StartParamForAmiiboSettings amiibo_settings{
114 .param_1 = 0,
115 .applet_mode = system.GetFrontendAppletHolder().GetCabinetMode(),
116 .flags = Frontend::CabinetFlags::None,
117 .amiibo_settings_1 = 0,
118 .device_handle = 0,
119 .tag_info{},
120 .register_info{},
121 .amiibo_settings_3{},
122 };
123
124 std::vector<u8> argument_data(sizeof(arguments));
125 std::vector<u8> settings_data(sizeof(amiibo_settings));
126 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
127 std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings));
128 channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
129 channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
130}
131
132void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) {
133 struct MiiEditV3 {
134 Frontend::MiiEditAppletInputCommon common;
135 Frontend::MiiEditAppletInputV3 input;
136 };
137 static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size.");
138
139 MiiEditV3 mii_arguments{
140 .common =
141 {
142 .version = Frontend::MiiEditAppletVersion::Version3,
143 .applet_mode = Frontend::MiiEditAppletMode::ShowMiiEdit,
144 },
145 .input{},
146 };
147
148 std::vector<u8> argument_data(sizeof(mii_arguments));
149 std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments));
150
151 channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
152}
153
154void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) {
155 const CommonArguments arguments{
156 .arguments_version = CommonArgumentVersion::Version3,
157 .size = CommonArgumentSize::Version3,
158 .library_version = static_cast<u32>(Frontend::SwkbdAppletVersion::Version524301),
159 .theme_color = ThemeColor::BasicBlack,
160 .play_startup_sound = true,
161 .system_tick = system.CoreTiming().GetClockTicks(),
162 };
163
164 std::vector<char16_t> initial_string(0);
165
166 const Frontend::SwkbdConfigCommon swkbd_config{
167 .type = Frontend::SwkbdType::Qwerty,
168 .ok_text{},
169 .left_optional_symbol_key{},
170 .right_optional_symbol_key{},
171 .use_prediction = false,
172 .key_disable_flags{},
173 .initial_cursor_position = Frontend::SwkbdInitialCursorPosition::Start,
174 .header_text{},
175 .sub_text{},
176 .guide_text{},
177 .max_text_length = 500,
178 .min_text_length = 0,
179 .password_mode = Frontend::SwkbdPasswordMode::Disabled,
180 .text_draw_type = Frontend::SwkbdTextDrawType::Box,
181 .enable_return_button = true,
182 .use_utf8 = false,
183 .use_blur_background = true,
184 .initial_string_offset{},
185 .initial_string_length = static_cast<u32>(initial_string.size()),
186 .user_dictionary_offset{},
187 .user_dictionary_entries{},
188 .use_text_check = false,
189 };
190
191 Frontend::SwkbdConfigNew swkbd_config_new{};
192
193 std::vector<u8> argument_data(sizeof(arguments));
194 std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new));
195 std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t));
196
197 std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
198 std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config));
199 std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new,
200 sizeof(Frontend::SwkbdConfigNew));
201 std::memcpy(work_buffer.data(), initial_string.data(),
202 swkbd_config.initial_string_length * sizeof(char16_t));
203
204 channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
205 channel.Push(std::make_shared<IStorage>(system, std::move(swkbd_data)));
206 channel.Push(std::make_shared<IStorage>(system, std::move(work_buffer)));
207}
208
209} // namespace
210
211AppletManager::AppletManager(Core::System& system) : m_system(system) {}
212AppletManager::~AppletManager() {
213 this->Reset();
214}
215
216void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) {
217 std::scoped_lock lk{m_lock};
218
219 m_applets.emplace(applet->aruid, std::move(applet));
220}
221
222void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) {
223 std::shared_ptr<Applet> applet;
224 bool should_stop = false;
225 {
226 std::scoped_lock lk{m_lock};
227
228 const auto it = m_applets.find(aruid);
229 if (it == m_applets.end()) {
230 return;
231 }
232
233 applet = it->second;
234 m_applets.erase(it);
235
236 should_stop = m_applets.empty();
237 }
238
239 // Terminate process.
240 applet->process->Terminate();
241
242 // If there were no applets left, stop emulation.
243 if (should_stop) {
244 m_system.Exit();
245 }
246}
247
248void AppletManager::CreateAndInsertByFrontendAppletParameters(
249 AppletResourceUserId aruid, const FrontendAppletParameters& params) {
250 // TODO: this should be run inside AM so that the events will have a parent process
251 // TODO: have am create the guest process
252 auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system));
253
254 applet->aruid = aruid;
255 applet->program_id = params.program_id;
256 applet->applet_id = params.applet_id;
257 applet->type = params.applet_type;
258 applet->previous_program_index = params.previous_program_index;
259
260 // Push UserChannel data from previous application
261 if (params.launch_type == LaunchType::ApplicationInitiated) {
262 applet->user_channel_launch_parameter.swap(m_system.GetUserChannel());
263 }
264
265 // TODO: Read whether we need a preselected user from NACP?
266 // TODO: This can be done quite easily from loader
267 {
268 LaunchParameterAccountPreselectedUser lp{};
269
270 lp.magic = LaunchParameterAccountPreselectedUserMagic;
271 lp.is_account_selected = 1;
272
273 Account::ProfileManager profile_manager{};
274 const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user));
275 ASSERT(uuid.has_value() && uuid->IsValid());
276 lp.current_user = *uuid;
277
278 std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
279 std::memcpy(buffer.data(), &lp, buffer.size());
280
281 applet->preselected_user_launch_parameter.push_back(std::move(buffer));
282 }
283
284 // Starting from frontend, some applets require input data.
285 switch (applet->applet_id) {
286 case AppletId::Cabinet:
287 PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet));
288 break;
289 case AppletId::MiiEdit:
290 PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet));
291 break;
292 case AppletId::PhotoViewer:
293 PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet));
294 break;
295 case AppletId::SoftwareKeyboard:
296 PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet));
297 break;
298 case AppletId::Controller:
299 PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet));
300 break;
301 default:
302 break;
303 }
304
305 // Applet was started by frontend, so it is foreground.
306 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
307 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
308 applet->focus_state = FocusState::InFocus;
309
310 this->InsertApplet(std::move(applet));
311}
312
313std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const {
314 std::scoped_lock lk{m_lock};
315
316 if (const auto it = m_applets.find(aruid); it != m_applets.end()) {
317 return it->second;
318 }
319
320 return {};
321}
322
323void AppletManager::Reset() {
324 std::scoped_lock lk{m_lock};
325
326 m_applets.clear();
327}
328
329void AppletManager::RequestExit() {
330 std::scoped_lock lk{m_lock};
331
332 for (const auto& [aruid, applet] : m_applets) {
333 applet->message_queue.RequestExit();
334 }
335}
336
337void AppletManager::RequestResume() {
338 std::scoped_lock lk{m_lock};
339
340 for (const auto& [aruid, applet] : m_applets) {
341 applet->message_queue.RequestResume();
342 }
343}
344
345void AppletManager::OperationModeChanged() {
346 std::scoped_lock lk{m_lock};
347
348 for (const auto& [aruid, applet] : m_applets) {
349 applet->message_queue.OperationModeChanged();
350 }
351}
352
353void AppletManager::FocusStateChanged() {
354 std::scoped_lock lk{m_lock};
355
356 for (const auto& [aruid, applet] : m_applets) {
357 applet->message_queue.FocusStateChanged();
358 }
359}
360
361} // namespace Service::AM
diff --git a/src/core/hle/service/am/applet_manager.h b/src/core/hle/service/am/applet_manager.h
new file mode 100644
index 000000000..4875de309
--- /dev/null
+++ b/src/core/hle/service/am/applet_manager.h
@@ -0,0 +1,59 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <map>
7#include <mutex>
8
9#include "core/hle/service/am/applet.h"
10
11namespace Core {
12class System;
13}
14
15namespace Service::AM {
16
17enum class LaunchType {
18 FrontendInitiated,
19 ApplicationInitiated,
20};
21
22struct FrontendAppletParameters {
23 ProgramId program_id{};
24 AppletId applet_id{};
25 AppletType applet_type{};
26 LaunchType launch_type{};
27 s32 program_index{};
28 s32 previous_program_index{-1};
29};
30
31class AppletManager {
32public:
33 explicit AppletManager(Core::System& system);
34 ~AppletManager();
35
36 void InsertApplet(std::shared_ptr<Applet> applet);
37 void TerminateAndRemoveApplet(AppletResourceUserId aruid);
38
39 void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid,
40 const FrontendAppletParameters& params);
41 std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const;
42
43 void Reset();
44
45 void RequestExit();
46 void RequestResume();
47 void OperationModeChanged();
48 void FocusStateChanged();
49
50private:
51 Core::System& m_system;
52
53 mutable std::mutex m_lock{};
54 std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{};
55
56 // AudioController state goes here
57};
58
59} // namespace Service::AM
diff --git a/src/core/hle/service/am/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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet_message_queue.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9AppletMessageQueue::AppletMessageQueue(Core::System& system)
10 : service_context{system, "AppletMessageQueue"} {
11 on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
12 on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
13}
14
15AppletMessageQueue::~AppletMessageQueue() {
16 service_context.CloseEvent(on_new_message);
17 service_context.CloseEvent(on_operation_mode_changed);
18}
19
20Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
21 return on_new_message->GetReadableEvent();
22}
23
24Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
25 return on_operation_mode_changed->GetReadableEvent();
26}
27
28void AppletMessageQueue::PushMessage(AppletMessage msg) {
29 {
30 std::scoped_lock lk{lock};
31 messages.push(msg);
32 }
33 on_new_message->Signal();
34}
35
36AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
37 std::scoped_lock lk{lock};
38 if (messages.empty()) {
39 on_new_message->Clear();
40 return AppletMessage::None;
41 }
42 auto msg = messages.front();
43 messages.pop();
44 if (messages.empty()) {
45 on_new_message->Clear();
46 }
47 return msg;
48}
49
50std::size_t AppletMessageQueue::GetMessageCount() const {
51 std::scoped_lock lk{lock};
52 return messages.size();
53}
54
55void AppletMessageQueue::RequestExit() {
56 PushMessage(AppletMessage::Exit);
57}
58
59void AppletMessageQueue::RequestResume() {
60 PushMessage(AppletMessage::Resume);
61}
62
63void AppletMessageQueue::FocusStateChanged() {
64 PushMessage(AppletMessage::FocusStateChanged);
65}
66
67void AppletMessageQueue::OperationModeChanged() {
68 PushMessage(AppletMessage::OperationModeChanged);
69 PushMessage(AppletMessage::PerformanceModeChanged);
70 on_operation_mode_changed->Signal();
71}
72
73} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <queue>
7
8#include "core/hle/service/kernel_helpers.h"
9#include "core/hle/service/service.h"
10
11namespace Kernel {
12class KReadableEvent;
13} // namespace Kernel
14
15namespace Service::AM {
16
17class AppletMessageQueue {
18public:
19 // This is nn::am::AppletMessage
20 enum class AppletMessage : u32 {
21 None = 0,
22 ChangeIntoForeground = 1,
23 ChangeIntoBackground = 2,
24 Exit = 4,
25 ApplicationExited = 6,
26 FocusStateChanged = 15,
27 Resume = 16,
28 DetectShortPressingHomeButton = 20,
29 DetectLongPressingHomeButton = 21,
30 DetectShortPressingPowerButton = 22,
31 DetectMiddlePressingPowerButton = 23,
32 DetectLongPressingPowerButton = 24,
33 RequestToPrepareSleep = 25,
34 FinishedSleepSequence = 26,
35 SleepRequiredByHighTemperature = 27,
36 SleepRequiredByLowBattery = 28,
37 AutoPowerDown = 29,
38 OperationModeChanged = 30,
39 PerformanceModeChanged = 31,
40 DetectReceivingCecSystemStandby = 32,
41 SdCardRemoved = 33,
42 LaunchApplicationRequested = 50,
43 RequestToDisplay = 51,
44 ShowApplicationLogo = 55,
45 HideApplicationLogo = 56,
46 ForceHideApplicationLogo = 57,
47 FloatingApplicationDetected = 60,
48 DetectShortPressingCaptureButton = 90,
49 AlbumScreenShotTaken = 92,
50 AlbumRecordingSaved = 93,
51 };
52
53 explicit AppletMessageQueue(Core::System& system);
54 ~AppletMessageQueue();
55
56 Kernel::KReadableEvent& GetMessageReceiveEvent();
57 Kernel::KReadableEvent& GetOperationModeChangedEvent();
58 void PushMessage(AppletMessage msg);
59 AppletMessage PopMessage();
60 std::size_t GetMessageCount() const;
61 void RequestExit();
62 void RequestResume();
63 void FocusStateChanged();
64 void OperationModeChanged();
65
66private:
67 KernelHelpers::ServiceContext service_context;
68
69 Kernel::KEvent* on_new_message;
70 Kernel::KEvent* on_operation_mode_changed;
71
72 mutable std::mutex lock;
73 std::queue<AppletMessage> messages;
74};
75
76} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h"
5#include "core/hle/service/am/am.h" 4#include "core/hle/service/am/am.h"
5#include "core/hle/service/am/applet_manager.h"
6#include "core/hle/service/am/applet_oe.h" 6#include "core/hle/service/am/applet_oe.h"
7#include "core/hle/service/am/application_proxy.h"
7#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
8#include "core/hle/service/nvnflinger/nvnflinger.h"
9 9
10namespace Service::AM { 10namespace Service::AM {
11 11
12class IApplicationProxy final : public ServiceFramework<IApplicationProxy> { 12AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_)
13public: 13 : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_} {
14 explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_, 14 static const FunctionInfo functions[] = {
15 std::shared_ptr<AppletMessageQueue> msg_queue_, 15 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
16 Core::System& system_) 16 };
17 : ServiceFramework{system_, "IApplicationProxy"}, 17 RegisterHandlers(functions);
18 nvnflinger{nvnflinger_}, msg_queue{std::move(msg_queue_)} { 18}
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
22 {1, &IApplicationProxy::GetSelfController, "GetSelfController"},
23 {2, &IApplicationProxy::GetWindowController, "GetWindowController"},
24 {3, &IApplicationProxy::GetAudioController, "GetAudioController"},
25 {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"},
26 {10, nullptr, "GetProcessWindingController"},
27 {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
28 {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
29 {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
30 };
31 // clang-format on
32
33 RegisterHandlers(functions);
34 }
35
36private:
37 void GetAudioController(HLERequestContext& ctx) {
38 LOG_DEBUG(Service_AM, "called");
39
40 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
41 rb.Push(ResultSuccess);
42 rb.PushIpcInterface<IAudioController>(system);
43 }
44
45 void GetDisplayController(HLERequestContext& ctx) {
46 LOG_DEBUG(Service_AM, "called");
47
48 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
49 rb.Push(ResultSuccess);
50 rb.PushIpcInterface<IDisplayController>(system);
51 }
52
53 void GetDebugFunctions(HLERequestContext& ctx) {
54 LOG_DEBUG(Service_AM, "called");
55
56 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
57 rb.Push(ResultSuccess);
58 rb.PushIpcInterface<IDebugFunctions>(system);
59 }
60
61 void GetWindowController(HLERequestContext& ctx) {
62 LOG_DEBUG(Service_AM, "called");
63
64 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
65 rb.Push(ResultSuccess);
66 rb.PushIpcInterface<IWindowController>(system);
67 }
68
69 void GetSelfController(HLERequestContext& ctx) {
70 LOG_DEBUG(Service_AM, "called");
71
72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
73 rb.Push(ResultSuccess);
74 rb.PushIpcInterface<ISelfController>(system, nvnflinger);
75 }
76
77 void GetCommonStateGetter(HLERequestContext& ctx) {
78 LOG_DEBUG(Service_AM, "called");
79 19
80 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 20AppletOE::~AppletOE() = default;
81 rb.Push(ResultSuccess);
82 rb.PushIpcInterface<ICommonStateGetter>(system, msg_queue);
83 }
84 21
85 void GetLibraryAppletCreator(HLERequestContext& ctx) { 22void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
86 LOG_DEBUG(Service_AM, "called"); 23 LOG_DEBUG(Service_AM, "called");
87 24
25 if (const auto applet = GetAppletFromContext(ctx)) {
88 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 26 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
89 rb.Push(ResultSuccess); 27 rb.Push(ResultSuccess);
90 rb.PushIpcInterface<ILibraryAppletCreator>(system); 28 rb.PushIpcInterface<IApplicationProxy>(nvnflinger, applet, system);
91 } 29 } else {
92 30 UNIMPLEMENTED();
93 void GetApplicationFunctions(HLERequestContext& ctx) {
94 LOG_DEBUG(Service_AM, "called");
95 31
96 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 32 IPC::ResponseBuilder rb{ctx, 2};
97 rb.Push(ResultSuccess); 33 rb.Push(ResultUnknown);
98 rb.PushIpcInterface<IApplicationFunctions>(system);
99 } 34 }
100
101 Nvnflinger::Nvnflinger& nvnflinger;
102 std::shared_ptr<AppletMessageQueue> msg_queue;
103};
104
105void AppletOE::OpenApplicationProxy(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_AM, "called");
107
108 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
109 rb.Push(ResultSuccess);
110 rb.PushIpcInterface<IApplicationProxy>(nvnflinger, msg_queue, system);
111}
112
113AppletOE::AppletOE(Nvnflinger::Nvnflinger& nvnflinger_,
114 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_)
115 : ServiceFramework{system_, "appletOE"}, nvnflinger{nvnflinger_}, msg_queue{
116 std::move(msg_queue_)} {
117 static const FunctionInfo functions[] = {
118 {0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
119 };
120 RegisterHandlers(functions);
121} 35}
122 36
123AppletOE::~AppletOE() = default; 37std::shared_ptr<Applet> AppletOE::GetAppletFromContext(HLERequestContext& ctx) {
124 38 const auto aruid = ctx.GetPID();
125const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const { 39 return system.GetAppletManager().GetByAppletResourceUserId(aruid);
126 return msg_queue;
127} 40}
128 41
129} // namespace Service::AM 42} // 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;
18 18
19namespace AM { 19namespace AM {
20 20
21class AppletMessageQueue; 21struct Applet;
22 22
23class AppletOE final : public ServiceFramework<AppletOE> { 23class AppletOE final : public ServiceFramework<AppletOE> {
24public: 24public:
25 explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, 25 explicit AppletOE(Nvnflinger::Nvnflinger& nvnflinger_, Core::System& system_);
26 std::shared_ptr<AppletMessageQueue> msg_queue_, Core::System& system_);
27 ~AppletOE() override; 26 ~AppletOE() override;
28 27
29 const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
30
31private: 28private:
32 void OpenApplicationProxy(HLERequestContext& ctx); 29 void OpenApplicationProxy(HLERequestContext& ctx);
33 30
31 std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);
32
34 Nvnflinger::Nvnflinger& nvnflinger; 33 Nvnflinger::Nvnflinger& nvnflinger;
35 std::shared_ptr<AppletMessageQueue> msg_queue;
36}; 34};
37 35
38} // namespace AM 36} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cstring>
5
6#include "common/assert.h"
7#include "core/core.h"
8#include "core/frontend/applets/cabinet.h"
9#include "core/frontend/applets/controller.h"
10#include "core/frontend/applets/error.h"
11#include "core/frontend/applets/general_frontend.h"
12#include "core/frontend/applets/mii_edit.h"
13#include "core/frontend/applets/profile_select.h"
14#include "core/frontend/applets/software_keyboard.h"
15#include "core/frontend/applets/web_browser.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/service/am/am.h"
18#include "core/hle/service/am/applet_ae.h"
19#include "core/hle/service/am/applet_oe.h"
20#include "core/hle/service/am/applets/applet_cabinet.h"
21#include "core/hle/service/am/applets/applet_controller.h"
22#include "core/hle/service/am/applets/applet_error.h"
23#include "core/hle/service/am/applets/applet_general_backend.h"
24#include "core/hle/service/am/applets/applet_mii_edit.h"
25#include "core/hle/service/am/applets/applet_profile_select.h"
26#include "core/hle/service/am/applets/applet_software_keyboard.h"
27#include "core/hle/service/am/applets/applet_web_browser.h"
28#include "core/hle/service/am/applets/applets.h"
29#include "core/hle/service/sm/sm.h"
30
31namespace Service::AM::Applets {
32
33AppletDataBroker::AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_)
34 : system{system_}, applet_mode{applet_mode_}, service_context{system,
35 "ILibraryAppletAccessor"} {
36 state_changed_event = service_context.CreateEvent("ILibraryAppletAccessor:StateChangedEvent");
37 pop_out_data_event = service_context.CreateEvent("ILibraryAppletAccessor:PopDataOutEvent");
38 pop_interactive_out_data_event =
39 service_context.CreateEvent("ILibraryAppletAccessor:PopInteractiveDataOutEvent");
40}
41
42AppletDataBroker::~AppletDataBroker() {
43 service_context.CloseEvent(state_changed_event);
44 service_context.CloseEvent(pop_out_data_event);
45 service_context.CloseEvent(pop_interactive_out_data_event);
46}
47
48AppletDataBroker::RawChannelData AppletDataBroker::PeekDataToAppletForDebug() const {
49 std::vector<std::vector<u8>> out_normal;
50
51 for (const auto& storage : in_channel) {
52 out_normal.push_back(storage->GetData());
53 }
54
55 std::vector<std::vector<u8>> out_interactive;
56
57 for (const auto& storage : in_interactive_channel) {
58 out_interactive.push_back(storage->GetData());
59 }
60
61 return {std::move(out_normal), std::move(out_interactive)};
62}
63
64std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
65 if (out_channel.empty())
66 return nullptr;
67
68 auto out = std::move(out_channel.front());
69 out_channel.pop_front();
70 pop_out_data_event->Clear();
71 return out;
72}
73
74std::shared_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
75 if (in_channel.empty())
76 return nullptr;
77
78 auto out = std::move(in_channel.front());
79 in_channel.pop_front();
80 return out;
81}
82
83std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
84 if (out_interactive_channel.empty())
85 return nullptr;
86
87 auto out = std::move(out_interactive_channel.front());
88 out_interactive_channel.pop_front();
89 pop_interactive_out_data_event->Clear();
90 return out;
91}
92
93std::shared_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
94 if (in_interactive_channel.empty())
95 return nullptr;
96
97 auto out = std::move(in_interactive_channel.front());
98 in_interactive_channel.pop_front();
99 return out;
100}
101
102void AppletDataBroker::PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage) {
103 in_channel.emplace_back(std::move(storage));
104}
105
106void AppletDataBroker::PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage) {
107 out_channel.emplace_back(std::move(storage));
108 pop_out_data_event->Signal();
109}
110
111void AppletDataBroker::PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage) {
112 in_interactive_channel.emplace_back(std::move(storage));
113}
114
115void AppletDataBroker::PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage) {
116 out_interactive_channel.emplace_back(std::move(storage));
117 pop_interactive_out_data_event->Signal();
118}
119
120void AppletDataBroker::SignalStateChanged() {
121 state_changed_event->Signal();
122
123 switch (applet_mode) {
124 case LibraryAppletMode::AllForeground:
125 case LibraryAppletMode::AllForegroundInitiallyHidden: {
126 auto applet_oe = system.ServiceManager().GetService<AppletOE>("appletOE");
127 auto applet_ae = system.ServiceManager().GetService<AppletAE>("appletAE");
128
129 if (applet_oe) {
130 applet_oe->GetMessageQueue()->FocusStateChanged();
131 break;
132 }
133
134 if (applet_ae) {
135 applet_ae->GetMessageQueue()->FocusStateChanged();
136 break;
137 }
138 break;
139 }
140 default:
141 break;
142 }
143}
144
145Kernel::KReadableEvent& AppletDataBroker::GetNormalDataEvent() {
146 return pop_out_data_event->GetReadableEvent();
147}
148
149Kernel::KReadableEvent& AppletDataBroker::GetInteractiveDataEvent() {
150 return pop_interactive_out_data_event->GetReadableEvent();
151}
152
153Kernel::KReadableEvent& AppletDataBroker::GetStateChangedEvent() {
154 return state_changed_event->GetReadableEvent();
155}
156
157Applet::Applet(Core::System& system_, LibraryAppletMode applet_mode_)
158 : broker{system_, applet_mode_}, applet_mode{applet_mode_} {}
159
160Applet::~Applet() = default;
161
162void Applet::Initialize() {
163 const auto common = broker.PopNormalDataToApplet();
164 ASSERT(common != nullptr);
165
166 const auto common_data = common->GetData();
167
168 ASSERT(common_data.size() >= sizeof(CommonArguments));
169 std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
170
171 initialized = true;
172}
173
174AppletFrontendSet::AppletFrontendSet() = default;
175
176AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet,
177 ControllerApplet controller_applet, ErrorApplet error_applet,
178 MiiEdit mii_edit_,
179 ParentalControlsApplet parental_controls_applet,
180 PhotoViewer photo_viewer_, ProfileSelect profile_select_,
181 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
182 : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
183 error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
184 parental_controls{std::move(parental_controls_applet)},
185 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
186 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
187
188AppletFrontendSet::~AppletFrontendSet() = default;
189
190AppletFrontendSet::AppletFrontendSet(AppletFrontendSet&&) noexcept = default;
191
192AppletFrontendSet& AppletFrontendSet::operator=(AppletFrontendSet&&) noexcept = default;
193
194AppletManager::AppletManager(Core::System& system_) : system{system_} {}
195
196AppletManager::~AppletManager() = default;
197
198const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
199 return frontend;
200}
201
202NFP::CabinetMode AppletManager::GetCabinetMode() const {
203 return cabinet_mode;
204}
205
206AppletId AppletManager::GetCurrentAppletId() const {
207 return current_applet_id;
208}
209
210void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
211 if (set.cabinet != nullptr) {
212 frontend.cabinet = std::move(set.cabinet);
213 }
214
215 if (set.controller != nullptr) {
216 frontend.controller = std::move(set.controller);
217 }
218
219 if (set.error != nullptr) {
220 frontend.error = std::move(set.error);
221 }
222
223 if (set.mii_edit != nullptr) {
224 frontend.mii_edit = std::move(set.mii_edit);
225 }
226
227 if (set.parental_controls != nullptr) {
228 frontend.parental_controls = std::move(set.parental_controls);
229 }
230
231 if (set.photo_viewer != nullptr) {
232 frontend.photo_viewer = std::move(set.photo_viewer);
233 }
234
235 if (set.profile_select != nullptr) {
236 frontend.profile_select = std::move(set.profile_select);
237 }
238
239 if (set.software_keyboard != nullptr) {
240 frontend.software_keyboard = std::move(set.software_keyboard);
241 }
242
243 if (set.web_browser != nullptr) {
244 frontend.web_browser = std::move(set.web_browser);
245 }
246}
247
248void AppletManager::SetCabinetMode(NFP::CabinetMode mode) {
249 cabinet_mode = mode;
250}
251
252void AppletManager::SetCurrentAppletId(AppletId applet_id) {
253 current_applet_id = applet_id;
254}
255
256void AppletManager::SetDefaultAppletFrontendSet() {
257 ClearAll();
258 SetDefaultAppletsIfMissing();
259}
260
261void AppletManager::SetDefaultAppletsIfMissing() {
262 if (frontend.cabinet == nullptr) {
263 frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
264 }
265
266 if (frontend.controller == nullptr) {
267 frontend.controller =
268 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
269 }
270
271 if (frontend.error == nullptr) {
272 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
273 }
274
275 if (frontend.mii_edit == nullptr) {
276 frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>();
277 }
278
279 if (frontend.parental_controls == nullptr) {
280 frontend.parental_controls =
281 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
282 }
283
284 if (frontend.photo_viewer == nullptr) {
285 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
286 }
287
288 if (frontend.profile_select == nullptr) {
289 frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
290 }
291
292 if (frontend.software_keyboard == nullptr) {
293 frontend.software_keyboard =
294 std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
295 }
296
297 if (frontend.web_browser == nullptr) {
298 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
299 }
300}
301
302void AppletManager::ClearAll() {
303 frontend = {};
304}
305
306std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const {
307 switch (id) {
308 case AppletId::Auth:
309 return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
310 case AppletId::Cabinet:
311 return std::make_shared<Cabinet>(system, mode, *frontend.cabinet);
312 case AppletId::Controller:
313 return std::make_shared<Controller>(system, mode, *frontend.controller);
314 case AppletId::Error:
315 return std::make_shared<Error>(system, mode, *frontend.error);
316 case AppletId::ProfileSelect:
317 return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
318 case AppletId::SoftwareKeyboard:
319 return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
320 case AppletId::MiiEdit:
321 return std::make_shared<MiiEdit>(system, mode, *frontend.mii_edit);
322 case AppletId::Web:
323 case AppletId::Shop:
324 case AppletId::OfflineWeb:
325 case AppletId::LoginShare:
326 case AppletId::WebAuth:
327 return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser);
328 case AppletId::PhotoViewer:
329 return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer);
330 default:
331 UNIMPLEMENTED_MSG(
332 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
333 static_cast<u8>(id));
334 return std::make_shared<StubApplet>(system, id, mode);
335 }
336}
337
338} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <queue>
8
9#include "common/swap.h"
10#include "core/hle/service/kernel_helpers.h"
11
12union Result;
13
14namespace Core {
15class System;
16}
17
18namespace Core::Frontend {
19class CabinetApplet;
20class ControllerApplet;
21class ECommerceApplet;
22class ErrorApplet;
23class MiiEditApplet;
24class ParentalControlsApplet;
25class PhotoViewerApplet;
26class ProfileSelectApplet;
27class SoftwareKeyboardApplet;
28class WebBrowserApplet;
29} // namespace Core::Frontend
30
31namespace Kernel {
32class KernelCore;
33class KEvent;
34class KReadableEvent;
35} // namespace Kernel
36
37namespace Service::NFP {
38enum class CabinetMode : u8;
39} // namespace Service::NFP
40
41namespace Service::AM {
42
43class IStorage;
44
45namespace Applets {
46
47enum class AppletId : u32 {
48 None = 0x00,
49 Application = 0x01,
50 OverlayDisplay = 0x02,
51 QLaunch = 0x03,
52 Starter = 0x04,
53 Auth = 0x0A,
54 Cabinet = 0x0B,
55 Controller = 0x0C,
56 DataErase = 0x0D,
57 Error = 0x0E,
58 NetConnect = 0x0F,
59 ProfileSelect = 0x10,
60 SoftwareKeyboard = 0x11,
61 MiiEdit = 0x12,
62 Web = 0x13,
63 Shop = 0x14,
64 PhotoViewer = 0x15,
65 Settings = 0x16,
66 OfflineWeb = 0x17,
67 LoginShare = 0x18,
68 WebAuth = 0x19,
69 MyPage = 0x1A,
70};
71
72enum class AppletProgramId : u64 {
73 QLaunch = 0x0100000000001000ull,
74 Auth = 0x0100000000001001ull,
75 Cabinet = 0x0100000000001002ull,
76 Controller = 0x0100000000001003ull,
77 DataErase = 0x0100000000001004ull,
78 Error = 0x0100000000001005ull,
79 NetConnect = 0x0100000000001006ull,
80 ProfileSelect = 0x0100000000001007ull,
81 SoftwareKeyboard = 0x0100000000001008ull,
82 MiiEdit = 0x0100000000001009ull,
83 Web = 0x010000000000100Aull,
84 Shop = 0x010000000000100Bull,
85 OverlayDisplay = 0x010000000000100Cull,
86 PhotoViewer = 0x010000000000100Dull,
87 Settings = 0x010000000000100Eull,
88 OfflineWeb = 0x010000000000100Full,
89 LoginShare = 0x0100000000001010ull,
90 WebAuth = 0x0100000000001011ull,
91 Starter = 0x0100000000001012ull,
92 MyPage = 0x0100000000001013ull,
93 MaxProgramId = 0x0100000000001FFFull,
94};
95
96enum class LibraryAppletMode : u32 {
97 AllForeground = 0,
98 Background = 1,
99 NoUI = 2,
100 BackgroundIndirectDisplay = 3,
101 AllForegroundInitiallyHidden = 4,
102};
103
104enum class CommonArgumentVersion : u32 {
105 Version0,
106 Version1,
107 Version2,
108 Version3,
109};
110
111enum class CommonArgumentSize : u32 {
112 Version3 = 0x20,
113};
114
115enum class ThemeColor : u32 {
116 BasicWhite = 0,
117 BasicBlack = 3,
118};
119
120struct CommonArguments {
121 CommonArgumentVersion arguments_version;
122 CommonArgumentSize size;
123 u32 library_version;
124 ThemeColor theme_color;
125 bool play_startup_sound;
126 u64_le system_tick;
127};
128static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
129
130class AppletDataBroker final {
131public:
132 explicit AppletDataBroker(Core::System& system_, LibraryAppletMode applet_mode_);
133 ~AppletDataBroker();
134
135 struct RawChannelData {
136 std::vector<std::vector<u8>> normal;
137 std::vector<std::vector<u8>> interactive;
138 };
139
140 // Retrieves but does not pop the data sent to applet.
141 RawChannelData PeekDataToAppletForDebug() const;
142
143 std::shared_ptr<IStorage> PopNormalDataToGame();
144 std::shared_ptr<IStorage> PopNormalDataToApplet();
145
146 std::shared_ptr<IStorage> PopInteractiveDataToGame();
147 std::shared_ptr<IStorage> PopInteractiveDataToApplet();
148
149 void PushNormalDataFromGame(std::shared_ptr<IStorage>&& storage);
150 void PushNormalDataFromApplet(std::shared_ptr<IStorage>&& storage);
151
152 void PushInteractiveDataFromGame(std::shared_ptr<IStorage>&& storage);
153 void PushInteractiveDataFromApplet(std::shared_ptr<IStorage>&& storage);
154
155 void SignalStateChanged();
156
157 Kernel::KReadableEvent& GetNormalDataEvent();
158 Kernel::KReadableEvent& GetInteractiveDataEvent();
159 Kernel::KReadableEvent& GetStateChangedEvent();
160
161private:
162 Core::System& system;
163 LibraryAppletMode applet_mode;
164
165 KernelHelpers::ServiceContext service_context;
166
167 // Queues are named from applet's perspective
168
169 // PopNormalDataToApplet and PushNormalDataFromGame
170 std::deque<std::shared_ptr<IStorage>> in_channel;
171
172 // PopNormalDataToGame and PushNormalDataFromApplet
173 std::deque<std::shared_ptr<IStorage>> out_channel;
174
175 // PopInteractiveDataToApplet and PushInteractiveDataFromGame
176 std::deque<std::shared_ptr<IStorage>> in_interactive_channel;
177
178 // PopInteractiveDataToGame and PushInteractiveDataFromApplet
179 std::deque<std::shared_ptr<IStorage>> out_interactive_channel;
180
181 Kernel::KEvent* state_changed_event;
182
183 // Signaled on PushNormalDataFromApplet
184 Kernel::KEvent* pop_out_data_event;
185
186 // Signaled on PushInteractiveDataFromApplet
187 Kernel::KEvent* pop_interactive_out_data_event;
188};
189
190class Applet {
191public:
192 explicit Applet(Core::System& system_, LibraryAppletMode applet_mode_);
193 virtual ~Applet();
194
195 virtual void Initialize();
196
197 virtual bool TransactionComplete() const = 0;
198 virtual Result GetStatus() const = 0;
199 virtual void ExecuteInteractive() = 0;
200 virtual void Execute() = 0;
201 virtual Result RequestExit() = 0;
202
203 AppletDataBroker& GetBroker() {
204 return broker;
205 }
206
207 const AppletDataBroker& GetBroker() const {
208 return broker;
209 }
210
211 LibraryAppletMode GetLibraryAppletMode() const {
212 return applet_mode;
213 }
214
215 bool IsInitialized() const {
216 return initialized;
217 }
218
219protected:
220 CommonArguments common_args{};
221 AppletDataBroker broker;
222 LibraryAppletMode applet_mode;
223 bool initialized = false;
224};
225
226struct AppletFrontendSet {
227 using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
228 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
229 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
230 using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
231 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
232 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
233 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
234 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
235 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
236
237 AppletFrontendSet();
238 AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
239 ErrorApplet error_applet, MiiEdit mii_edit_,
240 ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
241 ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
242 WebBrowser web_browser_);
243 ~AppletFrontendSet();
244
245 AppletFrontendSet(const AppletFrontendSet&) = delete;
246 AppletFrontendSet& operator=(const AppletFrontendSet&) = delete;
247
248 AppletFrontendSet(AppletFrontendSet&&) noexcept;
249 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
250
251 CabinetApplet cabinet;
252 ControllerApplet controller;
253 ErrorApplet error;
254 MiiEdit mii_edit;
255 ParentalControlsApplet parental_controls;
256 PhotoViewer photo_viewer;
257 ProfileSelect profile_select;
258 SoftwareKeyboard software_keyboard;
259 WebBrowser web_browser;
260};
261
262class AppletManager {
263public:
264 explicit AppletManager(Core::System& system_);
265 ~AppletManager();
266
267 const AppletFrontendSet& GetAppletFrontendSet() const;
268 NFP::CabinetMode GetCabinetMode() const;
269 AppletId GetCurrentAppletId() const;
270
271 void SetAppletFrontendSet(AppletFrontendSet set);
272 void SetCabinetMode(NFP::CabinetMode mode);
273 void SetCurrentAppletId(AppletId applet_id);
274 void SetDefaultAppletFrontendSet();
275 void SetDefaultAppletsIfMissing();
276 void ClearAll();
277
278 std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
279
280private:
281 AppletId current_applet_id{};
282 NFP::CabinetMode cabinet_mode{};
283
284 AppletFrontendSet frontend;
285 Core::System& system;
286};
287
288} // namespace Applets
289} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/application_creator.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IApplicationCreator::IApplicationCreator(Core::System& system_)
10 : ServiceFramework{system_, "IApplicationCreator"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "CreateApplication"},
14 {1, nullptr, "PopLaunchRequestedApplication"},
15 {10, nullptr, "CreateSystemApplication"},
16 {100, nullptr, "PopFloatingApplicationForDevelopment"},
17 };
18 // clang-format on
19
20 RegisterHandlers(functions);
21}
22
23IApplicationCreator::~IApplicationCreator() = default;
24
25} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
11public:
12 explicit IApplicationCreator(Core::System& system_);
13 ~IApplicationCreator() override;
14};
15
16} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "common/uuid.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
8#include "core/file_sys/registered_cache.h"
9#include "core/file_sys/savedata_factory.h"
10#include "core/hle/service/acc/profile_manager.h"
11#include "core/hle/service/am/am_results.h"
12#include "core/hle/service/am/applet.h"
13#include "core/hle/service/am/application_functions.h"
14#include "core/hle/service/am/storage.h"
15#include "core/hle/service/filesystem/filesystem.h"
16#include "core/hle/service/filesystem/save_data_controller.h"
17#include "core/hle/service/ipc_helpers.h"
18#include "core/hle/service/ns/ns.h"
19#include "core/hle/service/sm/sm.h"
20
21namespace Service::AM {
22
23enum class LaunchParameterKind : u32 {
24 UserChannel = 1,
25 AccountPreselectedUser = 2,
26};
27
28IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_)
29 : ServiceFramework{system_, "IApplicationFunctions"}, applet{std::move(applet_)} {
30 // clang-format off
31 static const FunctionInfo functions[] = {
32 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
33 {10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
34 {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
35 {12, nullptr, "CreateApplicationAndRequestToStart"},
36 {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
37 {14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
38 {15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
39 {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
40 {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
41 {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
42 {23, &IApplicationFunctions::GetDisplayVersion, "GetDisplayVersion"},
43 {24, nullptr, "GetLaunchStorageInfoForDebug"},
44 {25, &IApplicationFunctions::ExtendSaveData, "ExtendSaveData"},
45 {26, &IApplicationFunctions::GetSaveDataSize, "GetSaveDataSize"},
46 {27, &IApplicationFunctions::CreateCacheStorage, "CreateCacheStorage"},
47 {28, &IApplicationFunctions::GetSaveDataSizeMax, "GetSaveDataSizeMax"},
48 {29, nullptr, "GetCacheStorageMax"},
49 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
50 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
51 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
52 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
53 {34, nullptr, "SelectApplicationLicense"},
54 {35, nullptr, "GetDeviceSaveDataSizeMax"},
55 {36, nullptr, "GetLimitedApplicationLicense"},
56 {37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
57 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
58 {50, &IApplicationFunctions::GetPseudoDeviceId, "GetPseudoDeviceId"},
59 {60, nullptr, "SetMediaPlaybackStateForApplication"},
60 {65, &IApplicationFunctions::IsGamePlayRecordingSupported, "IsGamePlayRecordingSupported"},
61 {66, &IApplicationFunctions::InitializeGamePlayRecording, "InitializeGamePlayRecording"},
62 {67, &IApplicationFunctions::SetGamePlayRecordingState, "SetGamePlayRecordingState"},
63 {68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
64 {70, nullptr, "RequestToShutdown"},
65 {71, nullptr, "RequestToReboot"},
66 {72, nullptr, "RequestToSleep"},
67 {80, nullptr, "ExitAndRequestToShowThanksMessage"},
68 {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
69 {100, &IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer, "InitializeApplicationCopyrightFrameBuffer"},
70 {101, &IApplicationFunctions::SetApplicationCopyrightImage, "SetApplicationCopyrightImage"},
71 {102, &IApplicationFunctions::SetApplicationCopyrightVisibility, "SetApplicationCopyrightVisibility"},
72 {110, &IApplicationFunctions::QueryApplicationPlayStatistics, "QueryApplicationPlayStatistics"},
73 {111, &IApplicationFunctions::QueryApplicationPlayStatisticsByUid, "QueryApplicationPlayStatisticsByUid"},
74 {120, &IApplicationFunctions::ExecuteProgram, "ExecuteProgram"},
75 {121, &IApplicationFunctions::ClearUserChannel, "ClearUserChannel"},
76 {122, &IApplicationFunctions::UnpopToUserChannel, "UnpopToUserChannel"},
77 {123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
78 {124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
79 {130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
80 {131, nullptr, "SetDelayTimeToAbortOnGpuError"},
81 {140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
82 {141, &IApplicationFunctions::TryPopFromFriendInvitationStorageChannel, "TryPopFromFriendInvitationStorageChannel"},
83 {150, &IApplicationFunctions::GetNotificationStorageChannelEvent, "GetNotificationStorageChannelEvent"},
84 {151, nullptr, "TryPopFromNotificationStorageChannel"},
85 {160, &IApplicationFunctions::GetHealthWarningDisappearedSystemEvent, "GetHealthWarningDisappearedSystemEvent"},
86 {170, nullptr, "SetHdcpAuthenticationActivated"},
87 {180, nullptr, "GetLaunchRequiredVersion"},
88 {181, nullptr, "UpgradeLaunchRequiredVersion"},
89 {190, nullptr, "SendServerMaintenanceOverlayNotification"},
90 {200, nullptr, "GetLastApplicationExitReason"},
91 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
92 {1000, nullptr, "CreateMovieMaker"},
93 {1001, &IApplicationFunctions::PrepareForJit, "PrepareForJit"},
94 };
95 // clang-format on
96
97 RegisterHandlers(functions);
98}
99
100IApplicationFunctions::~IApplicationFunctions() = default;
101
102void IApplicationFunctions::EnableApplicationCrashReport(HLERequestContext& ctx) {
103 LOG_WARNING(Service_AM, "(STUBBED) called");
104
105 std::scoped_lock lk{applet->lock};
106 applet->application_crash_report_enabled = true;
107
108 IPC::ResponseBuilder rb{ctx, 2};
109 rb.Push(ResultSuccess);
110}
111
112void IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx) {
113 LOG_WARNING(Service_AM, "(STUBBED) called");
114
115 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(ResultSuccess);
117}
118
119void IApplicationFunctions::SetApplicationCopyrightImage(HLERequestContext& ctx) {
120 LOG_WARNING(Service_AM, "(STUBBED) called");
121
122 IPC::ResponseBuilder rb{ctx, 2};
123 rb.Push(ResultSuccess);
124}
125
126void IApplicationFunctions::SetApplicationCopyrightVisibility(HLERequestContext& ctx) {
127 IPC::RequestParser rp{ctx};
128 const auto is_visible = rp.Pop<bool>();
129
130 LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", is_visible);
131
132 IPC::ResponseBuilder rb{ctx, 2};
133 rb.Push(ResultSuccess);
134}
135
136void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
137 LOG_WARNING(Service_AM, "(STUBBED) called");
138
139 std::scoped_lock lk{applet->lock};
140 applet->home_button_long_pressed_blocked = true;
141 applet->home_button_short_pressed_blocked = true;
142
143 IPC::ResponseBuilder rb{ctx, 2};
144 rb.Push(ResultSuccess);
145}
146
147void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx) {
148 LOG_WARNING(Service_AM, "(STUBBED) called");
149
150 std::scoped_lock lk{applet->lock};
151 applet->home_button_long_pressed_blocked = false;
152 applet->home_button_short_pressed_blocked = false;
153
154 IPC::ResponseBuilder rb{ctx, 2};
155 rb.Push(ResultSuccess);
156}
157
158void IApplicationFunctions::BeginBlockingHomeButton(HLERequestContext& ctx) {
159 LOG_WARNING(Service_AM, "(STUBBED) called");
160
161 std::scoped_lock lk{applet->lock};
162 applet->home_button_long_pressed_blocked = true;
163 applet->home_button_short_pressed_blocked = true;
164 applet->home_button_double_click_enabled = true;
165
166 IPC::ResponseBuilder rb{ctx, 2};
167 rb.Push(ResultSuccess);
168}
169
170void IApplicationFunctions::EndBlockingHomeButton(HLERequestContext& ctx) {
171 LOG_WARNING(Service_AM, "(STUBBED) called");
172
173 std::scoped_lock lk{applet->lock};
174 applet->home_button_long_pressed_blocked = false;
175 applet->home_button_short_pressed_blocked = false;
176 applet->home_button_double_click_enabled = false;
177
178 IPC::ResponseBuilder rb{ctx, 2};
179 rb.Push(ResultSuccess);
180}
181
182void IApplicationFunctions::PopLaunchParameter(HLERequestContext& ctx) {
183 IPC::RequestParser rp{ctx};
184 const auto kind = rp.PopEnum<LaunchParameterKind>();
185
186 LOG_INFO(Service_AM, "called, kind={:08X}", kind);
187
188 std::scoped_lock lk{applet->lock};
189
190 auto& channel = kind == LaunchParameterKind::UserChannel
191 ? applet->user_channel_launch_parameter
192 : applet->preselected_user_launch_parameter;
193
194 if (channel.empty()) {
195 LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!", kind);
196 IPC::ResponseBuilder rb{ctx, 2};
197 rb.Push(AM::ResultNoDataInChannel);
198 return;
199 }
200
201 auto data = channel.back();
202 channel.pop_back();
203
204 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
205 rb.Push(ResultSuccess);
206 rb.PushIpcInterface<IStorage>(system, std::move(data));
207}
208
209void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx) {
210 LOG_WARNING(Service_AM, "(STUBBED) called");
211
212 IPC::ResponseBuilder rb{ctx, 2};
213 rb.Push(ResultSuccess);
214}
215
216void IApplicationFunctions::EnsureSaveData(HLERequestContext& ctx) {
217 IPC::RequestParser rp{ctx};
218 u128 user_id = rp.PopRaw<u128>();
219
220 LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
221
222 FileSys::SaveDataAttribute attribute{};
223 attribute.title_id = applet->program_id;
224 attribute.user_id = user_id;
225 attribute.type = FileSys::SaveDataType::SaveData;
226
227 FileSys::VirtualDir save_data{};
228 const auto res = system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
229 &save_data, FileSys::SaveDataSpaceId::NandUser, attribute);
230
231 IPC::ResponseBuilder rb{ctx, 4};
232 rb.Push(res);
233 rb.Push<u64>(0);
234}
235
236void IApplicationFunctions::SetTerminateResult(HLERequestContext& ctx) {
237 // Takes an input u32 Result, no output.
238 // For example, in some cases official apps use this with error 0x2A2 then
239 // uses svcBreak.
240
241 IPC::RequestParser rp{ctx};
242 u32 result = rp.Pop<u32>();
243 LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
244
245 std::scoped_lock lk{applet->lock};
246 applet->terminate_result = Result(result);
247
248 IPC::ResponseBuilder rb{ctx, 2};
249 rb.Push(ResultSuccess);
250}
251
252void IApplicationFunctions::GetDisplayVersion(HLERequestContext& ctx) {
253 LOG_DEBUG(Service_AM, "called");
254
255 std::array<u8, 0x10> version_string{};
256
257 const auto res = [this] {
258 const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(),
259 system.GetContentProvider()};
260 auto metadata = pm.GetControlMetadata();
261 if (metadata.first != nullptr) {
262 return metadata;
263 }
264
265 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id),
266 system.GetFileSystemController(),
267 system.GetContentProvider()};
268 return pm_update.GetControlMetadata();
269 }();
270
271 if (res.first != nullptr) {
272 const auto& version = res.first->GetVersionString();
273 std::copy(version.begin(), version.end(), version_string.begin());
274 } else {
275 static constexpr char default_version[]{"1.0.0"};
276 std::memcpy(version_string.data(), default_version, sizeof(default_version));
277 }
278
279 IPC::ResponseBuilder rb{ctx, 6};
280 rb.Push(ResultSuccess);
281 rb.PushRaw(version_string);
282}
283
284void IApplicationFunctions::GetDesiredLanguage(HLERequestContext& ctx) {
285 // TODO(bunnei): This should be configurable
286 LOG_DEBUG(Service_AM, "called");
287
288 // Get supported languages from NACP, if possible
289 // Default to 0 (all languages supported)
290 u32 supported_languages = 0;
291
292 const auto res = [this] {
293 const FileSys::PatchManager pm{applet->program_id, system.GetFileSystemController(),
294 system.GetContentProvider()};
295 auto metadata = pm.GetControlMetadata();
296 if (metadata.first != nullptr) {
297 return metadata;
298 }
299
300 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(applet->program_id),
301 system.GetFileSystemController(),
302 system.GetContentProvider()};
303 return pm_update.GetControlMetadata();
304 }();
305
306 if (res.first != nullptr) {
307 supported_languages = res.first->GetSupportedLanguages();
308 }
309
310 // Call IApplicationManagerInterface implementation.
311 auto& service_manager = system.ServiceManager();
312 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
313 auto app_man = ns_am2->GetApplicationManagerInterface();
314
315 // Get desired application language
316 u8 desired_language{};
317 const auto res_lang =
318 app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
319 if (res_lang != ResultSuccess) {
320 IPC::ResponseBuilder rb{ctx, 2};
321 rb.Push(res_lang);
322 return;
323 }
324
325 // Convert to settings language code.
326 u64 language_code{};
327 const auto res_code =
328 app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
329 if (res_code != ResultSuccess) {
330 IPC::ResponseBuilder rb{ctx, 2};
331 rb.Push(res_code);
332 return;
333 }
334
335 LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
336
337 IPC::ResponseBuilder rb{ctx, 4};
338 rb.Push(ResultSuccess);
339 rb.Push(language_code);
340}
341
342void IApplicationFunctions::IsGamePlayRecordingSupported(HLERequestContext& ctx) {
343 LOG_WARNING(Service_AM, "(STUBBED) called");
344
345 IPC::ResponseBuilder rb{ctx, 3};
346 rb.Push(ResultSuccess);
347 rb.Push(applet->gameplay_recording_supported);
348}
349
350void IApplicationFunctions::InitializeGamePlayRecording(HLERequestContext& ctx) {
351 LOG_WARNING(Service_AM, "(STUBBED) called");
352
353 IPC::ResponseBuilder rb{ctx, 2};
354 rb.Push(ResultSuccess);
355}
356
357void IApplicationFunctions::SetGamePlayRecordingState(HLERequestContext& ctx) {
358 LOG_WARNING(Service_AM, "(STUBBED) called");
359
360 IPC::RequestParser rp{ctx};
361
362 std::scoped_lock lk{applet->lock};
363 applet->gameplay_recording_state = rp.PopRaw<GameplayRecordingState>();
364
365 IPC::ResponseBuilder rb{ctx, 2};
366 rb.Push(ResultSuccess);
367}
368
369void IApplicationFunctions::NotifyRunning(HLERequestContext& ctx) {
370 LOG_WARNING(Service_AM, "(STUBBED) called");
371
372 std::scoped_lock lk{applet->lock};
373 applet->is_running = true;
374
375 IPC::ResponseBuilder rb{ctx, 3};
376 rb.Push(ResultSuccess);
377 rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
378}
379
380void IApplicationFunctions::GetPseudoDeviceId(HLERequestContext& ctx) {
381 LOG_WARNING(Service_AM, "(STUBBED) called");
382
383 IPC::ResponseBuilder rb{ctx, 6};
384 rb.Push(ResultSuccess);
385
386 // Returns a 128-bit UUID
387 rb.Push<u64>(0);
388 rb.Push<u64>(0);
389}
390
391void IApplicationFunctions::ExtendSaveData(HLERequestContext& ctx) {
392 struct Parameters {
393 FileSys::SaveDataType type;
394 u128 user_id;
395 u64 new_normal_size;
396 u64 new_journal_size;
397 };
398 static_assert(sizeof(Parameters) == 40);
399
400 IPC::RequestParser rp{ctx};
401 const auto [type, user_id, new_normal_size, new_journal_size] = rp.PopRaw<Parameters>();
402
403 LOG_DEBUG(Service_AM,
404 "called with type={:02X}, user_id={:016X}{:016X}, new_normal={:016X}, "
405 "new_journal={:016X}",
406 static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
407
408 system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
409 type, applet->program_id, user_id, {new_normal_size, new_journal_size});
410
411 IPC::ResponseBuilder rb{ctx, 4};
412 rb.Push(ResultSuccess);
413
414 // The following value is used upon failure to help the system recover.
415 // Since we always succeed, this should be 0.
416 rb.Push<u64>(0);
417}
418
419void IApplicationFunctions::GetSaveDataSize(HLERequestContext& ctx) {
420 struct Parameters {
421 FileSys::SaveDataType type;
422 u128 user_id;
423 };
424 static_assert(sizeof(Parameters) == 24);
425
426 IPC::RequestParser rp{ctx};
427 const auto [type, user_id] = rp.PopRaw<Parameters>();
428
429 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", type, user_id[1],
430 user_id[0]);
431
432 const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
433 type, applet->program_id, user_id);
434
435 IPC::ResponseBuilder rb{ctx, 6};
436 rb.Push(ResultSuccess);
437 rb.Push(size.normal);
438 rb.Push(size.journal);
439}
440
441void IApplicationFunctions::CreateCacheStorage(HLERequestContext& ctx) {
442 struct InputParameters {
443 u16 index;
444 s64 size;
445 s64 journal_size;
446 };
447 static_assert(sizeof(InputParameters) == 24);
448
449 struct OutputParameters {
450 u32 storage_target;
451 u64 required_size;
452 };
453 static_assert(sizeof(OutputParameters) == 16);
454
455 IPC::RequestParser rp{ctx};
456 const auto params = rp.PopRaw<InputParameters>();
457
458 LOG_WARNING(Service_AM, "(STUBBED) called with index={}, size={:#x}, journal_size={:#x}",
459 params.index, params.size, params.journal_size);
460
461 const OutputParameters resp{
462 .storage_target = 1,
463 .required_size = 0,
464 };
465
466 IPC::ResponseBuilder rb{ctx, 6};
467 rb.Push(ResultSuccess);
468 rb.PushRaw(resp);
469}
470
471void IApplicationFunctions::GetSaveDataSizeMax(HLERequestContext& ctx) {
472 LOG_WARNING(Service_AM, "(STUBBED) called");
473
474 constexpr u64 size_max_normal = 0xFFFFFFF;
475 constexpr u64 size_max_journal = 0xFFFFFFF;
476
477 IPC::ResponseBuilder rb{ctx, 6};
478 rb.Push(ResultSuccess);
479 rb.Push(size_max_normal);
480 rb.Push(size_max_journal);
481}
482
483void IApplicationFunctions::QueryApplicationPlayStatistics(HLERequestContext& ctx) {
484 LOG_WARNING(Service_AM, "(STUBBED) called");
485
486 IPC::ResponseBuilder rb{ctx, 3};
487 rb.Push(ResultSuccess);
488 rb.Push<u32>(0);
489}
490
491void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx) {
492 LOG_WARNING(Service_AM, "(STUBBED) called");
493
494 IPC::ResponseBuilder rb{ctx, 3};
495 rb.Push(ResultSuccess);
496 rb.Push<u32>(0);
497}
498
499void IApplicationFunctions::ExecuteProgram(HLERequestContext& ctx) {
500 LOG_WARNING(Service_AM, "(STUBBED) called");
501
502 IPC::RequestParser rp{ctx};
503 [[maybe_unused]] const auto unk_1 = rp.Pop<u32>();
504 [[maybe_unused]] const auto unk_2 = rp.Pop<u32>();
505 const auto program_index = rp.Pop<u64>();
506
507 IPC::ResponseBuilder rb{ctx, 2};
508 rb.Push(ResultSuccess);
509
510 // Swap user channel ownership into the system so that it will be preserved
511 system.GetUserChannel().swap(applet->user_channel_launch_parameter);
512 system.ExecuteProgram(program_index);
513}
514
515void IApplicationFunctions::ClearUserChannel(HLERequestContext& ctx) {
516 LOG_DEBUG(Service_AM, "called");
517
518 applet->user_channel_launch_parameter.clear();
519
520 IPC::ResponseBuilder rb{ctx, 2};
521 rb.Push(ResultSuccess);
522}
523
524void IApplicationFunctions::UnpopToUserChannel(HLERequestContext& ctx) {
525 LOG_DEBUG(Service_AM, "called");
526
527 IPC::RequestParser rp{ctx};
528 const auto storage = rp.PopIpcInterface<IStorage>().lock();
529 if (storage) {
530 applet->user_channel_launch_parameter.push_back(storage->GetData());
531 }
532
533 IPC::ResponseBuilder rb{ctx, 2};
534 rb.Push(ResultSuccess);
535}
536
537void IApplicationFunctions::GetPreviousProgramIndex(HLERequestContext& ctx) {
538 LOG_WARNING(Service_AM, "(STUBBED) called");
539
540 IPC::ResponseBuilder rb{ctx, 3};
541 rb.Push(ResultSuccess);
542 rb.Push<s32>(applet->previous_program_index);
543}
544
545void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx) {
546 LOG_WARNING(Service_AM, "(STUBBED) called");
547
548 IPC::ResponseBuilder rb{ctx, 2, 1};
549 rb.Push(ResultSuccess);
550 rb.PushCopyObjects(applet->gpu_error_detected_event.GetHandle());
551}
552
553void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx) {
554 LOG_DEBUG(Service_AM, "called");
555
556 IPC::ResponseBuilder rb{ctx, 2, 1};
557 rb.Push(ResultSuccess);
558 rb.PushCopyObjects(applet->friend_invitation_storage_channel_event.GetHandle());
559}
560
561void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) {
562 LOG_DEBUG(Service_AM, "(STUBBED) called");
563
564 IPC::ResponseBuilder rb{ctx, 2};
565 rb.Push(AM::ResultNoDataInChannel);
566}
567
568void IApplicationFunctions::GetNotificationStorageChannelEvent(HLERequestContext& ctx) {
569 LOG_DEBUG(Service_AM, "called");
570
571 IPC::ResponseBuilder rb{ctx, 2, 1};
572 rb.Push(ResultSuccess);
573 rb.PushCopyObjects(applet->notification_storage_channel_event.GetHandle());
574}
575
576void IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx) {
577 LOG_DEBUG(Service_AM, "called");
578
579 IPC::ResponseBuilder rb{ctx, 2, 1};
580 rb.Push(ResultSuccess);
581 rb.PushCopyObjects(applet->health_warning_disappeared_system_event.GetHandle());
582}
583
584void IApplicationFunctions::PrepareForJit(HLERequestContext& ctx) {
585 LOG_WARNING(Service_AM, "(STUBBED) called");
586
587 std::scoped_lock lk{applet->lock};
588 applet->jit_service_launched = true;
589
590 IPC::ResponseBuilder rb{ctx, 2};
591 rb.Push(ResultSuccess);
592}
593
594} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11struct Applet;
12
13class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
14public:
15 explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
16 ~IApplicationFunctions() override;
17
18private:
19 void PopLaunchParameter(HLERequestContext& ctx);
20 void CreateApplicationAndRequestToStartForQuest(HLERequestContext& ctx);
21 void EnsureSaveData(HLERequestContext& ctx);
22 void SetTerminateResult(HLERequestContext& ctx);
23 void GetDisplayVersion(HLERequestContext& ctx);
24 void GetDesiredLanguage(HLERequestContext& ctx);
25 void IsGamePlayRecordingSupported(HLERequestContext& ctx);
26 void InitializeGamePlayRecording(HLERequestContext& ctx);
27 void SetGamePlayRecordingState(HLERequestContext& ctx);
28 void NotifyRunning(HLERequestContext& ctx);
29 void GetPseudoDeviceId(HLERequestContext& ctx);
30 void ExtendSaveData(HLERequestContext& ctx);
31 void GetSaveDataSize(HLERequestContext& ctx);
32 void CreateCacheStorage(HLERequestContext& ctx);
33 void GetSaveDataSizeMax(HLERequestContext& ctx);
34 void BeginBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
35 void EndBlockingHomeButtonShortAndLongPressed(HLERequestContext& ctx);
36 void BeginBlockingHomeButton(HLERequestContext& ctx);
37 void EndBlockingHomeButton(HLERequestContext& ctx);
38 void EnableApplicationCrashReport(HLERequestContext& ctx);
39 void InitializeApplicationCopyrightFrameBuffer(HLERequestContext& ctx);
40 void SetApplicationCopyrightImage(HLERequestContext& ctx);
41 void SetApplicationCopyrightVisibility(HLERequestContext& ctx);
42 void QueryApplicationPlayStatistics(HLERequestContext& ctx);
43 void QueryApplicationPlayStatisticsByUid(HLERequestContext& ctx);
44 void ExecuteProgram(HLERequestContext& ctx);
45 void ClearUserChannel(HLERequestContext& ctx);
46 void UnpopToUserChannel(HLERequestContext& ctx);
47 void GetPreviousProgramIndex(HLERequestContext& ctx);
48 void GetGpuErrorDetectedSystemEvent(HLERequestContext& ctx);
49 void GetFriendInvitationStorageChannelEvent(HLERequestContext& ctx);
50 void TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx);
51 void GetNotificationStorageChannelEvent(HLERequestContext& ctx);
52 void GetHealthWarningDisappearedSystemEvent(HLERequestContext& ctx);
53 void PrepareForJit(HLERequestContext& ctx);
54
55 const std::shared_ptr<Applet> applet;
56};
57
58} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet_common_functions.h"
5#include "core/hle/service/am/application_functions.h"
6#include "core/hle/service/am/application_proxy.h"
7#include "core/hle/service/am/audio_controller.h"
8#include "core/hle/service/am/common_state_getter.h"
9#include "core/hle/service/am/debug_functions.h"
10#include "core/hle/service/am/display_controller.h"
11#include "core/hle/service/am/library_applet_creator.h"
12#include "core/hle/service/am/library_applet_self_accessor.h"
13#include "core/hle/service/am/process_winding_controller.h"
14#include "core/hle/service/am/self_controller.h"
15#include "core/hle/service/am/window_controller.h"
16#include "core/hle/service/ipc_helpers.h"
17
18namespace Service::AM {
19
20IApplicationProxy::IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
21 std::shared_ptr<Applet> applet_, Core::System& system_)
22 : ServiceFramework{system_, "IApplicationProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
23 applet_)} {
24 // clang-format off
25 static const FunctionInfo functions[] = {
26 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
27 {1, &IApplicationProxy::GetSelfController, "GetSelfController"},
28 {2, &IApplicationProxy::GetWindowController, "GetWindowController"},
29 {3, &IApplicationProxy::GetAudioController, "GetAudioController"},
30 {4, &IApplicationProxy::GetDisplayController, "GetDisplayController"},
31 {10, &IApplicationProxy::GetProcessWindingController, "GetProcessWindingController"},
32 {11, &IApplicationProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
33 {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
34 {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
35 };
36 // clang-format on
37
38 RegisterHandlers(functions);
39}
40
41IApplicationProxy::~IApplicationProxy() = default;
42
43void IApplicationProxy::GetAudioController(HLERequestContext& ctx) {
44 LOG_DEBUG(Service_AM, "called");
45
46 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
47 rb.Push(ResultSuccess);
48 rb.PushIpcInterface<IAudioController>(system);
49}
50
51void IApplicationProxy::GetDisplayController(HLERequestContext& ctx) {
52 LOG_DEBUG(Service_AM, "called");
53
54 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
55 rb.Push(ResultSuccess);
56 rb.PushIpcInterface<IDisplayController>(system, applet);
57}
58
59void IApplicationProxy::GetProcessWindingController(HLERequestContext& ctx) {
60 LOG_DEBUG(Service_AM, "called");
61
62 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
63 rb.Push(ResultSuccess);
64 rb.PushIpcInterface<IProcessWindingController>(system, applet);
65}
66
67void IApplicationProxy::GetDebugFunctions(HLERequestContext& ctx) {
68 LOG_DEBUG(Service_AM, "called");
69
70 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
71 rb.Push(ResultSuccess);
72 rb.PushIpcInterface<IDebugFunctions>(system);
73}
74
75void IApplicationProxy::GetWindowController(HLERequestContext& ctx) {
76 LOG_DEBUG(Service_AM, "called");
77
78 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
79 rb.Push(ResultSuccess);
80 rb.PushIpcInterface<IWindowController>(system, applet);
81}
82
83void IApplicationProxy::GetSelfController(HLERequestContext& ctx) {
84 LOG_DEBUG(Service_AM, "called");
85
86 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
87 rb.Push(ResultSuccess);
88 rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
89}
90
91void IApplicationProxy::GetCommonStateGetter(HLERequestContext& ctx) {
92 LOG_DEBUG(Service_AM, "called");
93
94 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
95 rb.Push(ResultSuccess);
96 rb.PushIpcInterface<ICommonStateGetter>(system, applet);
97}
98
99void IApplicationProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
100 LOG_DEBUG(Service_AM, "called");
101
102 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
103 rb.Push(ResultSuccess);
104 rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
105}
106
107void IApplicationProxy::GetApplicationFunctions(HLERequestContext& ctx) {
108 LOG_DEBUG(Service_AM, "called");
109
110 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
111 rb.Push(ResultSuccess);
112 rb.PushIpcInterface<IApplicationFunctions>(system, applet);
113}
114
115} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
13public:
14 explicit IApplicationProxy(Nvnflinger::Nvnflinger& nvnflinger_,
15 std::shared_ptr<Applet> msg_queue_, Core::System& system_);
16 ~IApplicationProxy();
17
18private:
19 void GetAudioController(HLERequestContext& ctx);
20 void GetDisplayController(HLERequestContext& ctx);
21 void GetProcessWindingController(HLERequestContext& ctx);
22 void GetDebugFunctions(HLERequestContext& ctx);
23 void GetWindowController(HLERequestContext& ctx);
24 void GetSelfController(HLERequestContext& ctx);
25 void GetCommonStateGetter(HLERequestContext& ctx);
26 void GetLibraryAppletCreator(HLERequestContext& ctx);
27 void GetApplicationFunctions(HLERequestContext& ctx);
28
29 Nvnflinger::Nvnflinger& nvnflinger;
30 std::shared_ptr<Applet> applet;
31};
32
33} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/audio_controller.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IAudioController::IAudioController(Core::System& system_)
10 : ServiceFramework{system_, "IAudioController"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, &IAudioController::SetExpectedMasterVolume, "SetExpectedMasterVolume"},
14 {1, &IAudioController::GetMainAppletExpectedMasterVolume, "GetMainAppletExpectedMasterVolume"},
15 {2, &IAudioController::GetLibraryAppletExpectedMasterVolume, "GetLibraryAppletExpectedMasterVolume"},
16 {3, &IAudioController::ChangeMainAppletMasterVolume, "ChangeMainAppletMasterVolume"},
17 {4, &IAudioController::SetTransparentAudioRate, "SetTransparentVolumeRate"},
18 };
19 // clang-format on
20
21 RegisterHandlers(functions);
22}
23
24IAudioController::~IAudioController() = default;
25
26void IAudioController::SetExpectedMasterVolume(HLERequestContext& ctx) {
27 IPC::RequestParser rp{ctx};
28 const float main_applet_volume_tmp = rp.Pop<float>();
29 const float library_applet_volume_tmp = rp.Pop<float>();
30
31 LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
32 main_applet_volume_tmp, library_applet_volume_tmp);
33
34 // Ensure the volume values remain within the 0-100% range
35 main_applet_volume = std::clamp(main_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
36 library_applet_volume =
37 std::clamp(library_applet_volume_tmp, min_allowed_volume, max_allowed_volume);
38
39 IPC::ResponseBuilder rb{ctx, 2};
40 rb.Push(ResultSuccess);
41}
42
43void IAudioController::GetMainAppletExpectedMasterVolume(HLERequestContext& ctx) {
44 LOG_DEBUG(Service_AM, "called. main_applet_volume={}", main_applet_volume);
45 IPC::ResponseBuilder rb{ctx, 3};
46 rb.Push(ResultSuccess);
47 rb.Push(main_applet_volume);
48}
49
50void IAudioController::GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx) {
51 LOG_DEBUG(Service_AM, "called. library_applet_volume={}", library_applet_volume);
52 IPC::ResponseBuilder rb{ctx, 3};
53 rb.Push(ResultSuccess);
54 rb.Push(library_applet_volume);
55}
56
57void IAudioController::ChangeMainAppletMasterVolume(HLERequestContext& ctx) {
58 struct Parameters {
59 float volume;
60 s64 fade_time_ns;
61 };
62 static_assert(sizeof(Parameters) == 16);
63
64 IPC::RequestParser rp{ctx};
65 const auto parameters = rp.PopRaw<Parameters>();
66
67 LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", parameters.volume,
68 parameters.fade_time_ns);
69
70 main_applet_volume = std::clamp(parameters.volume, min_allowed_volume, max_allowed_volume);
71 fade_time_ns = std::chrono::nanoseconds{parameters.fade_time_ns};
72
73 IPC::ResponseBuilder rb{ctx, 2};
74 rb.Push(ResultSuccess);
75}
76
77void IAudioController::SetTransparentAudioRate(HLERequestContext& ctx) {
78 IPC::RequestParser rp{ctx};
79 const float transparent_volume_rate_tmp = rp.Pop<float>();
80
81 LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate_tmp);
82
83 // Clamp volume range to 0-100%.
84 transparent_volume_rate =
85 std::clamp(transparent_volume_rate_tmp, min_allowed_volume, max_allowed_volume);
86
87 IPC::ResponseBuilder rb{ctx, 2};
88 rb.Push(ResultSuccess);
89}
90
91} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class IAudioController final : public ServiceFramework<IAudioController> {
11public:
12 explicit IAudioController(Core::System& system_);
13 ~IAudioController() override;
14
15private:
16 void SetExpectedMasterVolume(HLERequestContext& ctx);
17 void GetMainAppletExpectedMasterVolume(HLERequestContext& ctx);
18 void GetLibraryAppletExpectedMasterVolume(HLERequestContext& ctx);
19 void ChangeMainAppletMasterVolume(HLERequestContext& ctx);
20 void SetTransparentAudioRate(HLERequestContext& ctx);
21
22 static constexpr float min_allowed_volume = 0.0f;
23 static constexpr float max_allowed_volume = 1.0f;
24
25 float main_applet_volume{0.25f};
26 float library_applet_volume{max_allowed_volume};
27 float transparent_volume_rate{min_allowed_volume};
28
29 // Volume transition fade time in nanoseconds.
30 // e.g. If the main applet volume was 0% and was changed to 50%
31 // with a fade of 50ns, then over the course of 50ns,
32 // the volume will gradually fade up to 50%
33 std::chrono::nanoseconds fade_time_ns{0};
34};
35
36} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/settings.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/applet.h"
7#include "core/hle/service/am/common_state_getter.h"
8#include "core/hle/service/am/lock_accessor.h"
9#include "core/hle/service/apm/apm_controller.h"
10#include "core/hle/service/apm/apm_interface.h"
11#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/pm/pm.h"
13#include "core/hle/service/sm/sm.h"
14#include "core/hle/service/vi/vi.h"
15
16namespace Service::AM {
17
18ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_)
19 : ServiceFramework{system_, "ICommonStateGetter"}, applet{std::move(applet_)} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
23 {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
24 {2, nullptr, "GetThisAppletKind"},
25 {3, nullptr, "AllowToEnterSleep"},
26 {4, nullptr, "DisallowToEnterSleep"},
27 {5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"},
28 {6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"},
29 {7, nullptr, "GetCradleStatus"},
30 {8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
31 {9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
32 {10, &ICommonStateGetter::RequestToAcquireSleepLock, "RequestToAcquireSleepLock"},
33 {11, nullptr, "ReleaseSleepLock"},
34 {12, nullptr, "ReleaseSleepLockTransiently"},
35 {13, &ICommonStateGetter::GetAcquiredSleepLockEvent, "GetAcquiredSleepLockEvent"},
36 {14, nullptr, "GetWakeupCount"},
37 {20, nullptr, "PushToGeneralChannel"},
38 {30, nullptr, "GetHomeButtonReaderLockAccessor"},
39 {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
40 {32, nullptr, "GetWriterLockAccessorEx"},
41 {40, nullptr, "GetCradleFwVersion"},
42 {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
43 {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
44 {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
45 {53, &ICommonStateGetter::BeginVrModeEx, "BeginVrModeEx"},
46 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
47 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
48 {59, nullptr, "SetVrPositionForDebug"},
49 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
50 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
51 {62, nullptr, "GetHdcpAuthenticationState"},
52 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
53 {64, nullptr, "SetTvPowerStateMatchingMode"},
54 {65, nullptr, "GetApplicationIdByContentActionName"},
55 {66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
56 {67, nullptr, "CancelCpuBoostMode"},
57 {68, &ICommonStateGetter::GetBuiltInDisplayType, "GetBuiltInDisplayType"},
58 {80, &ICommonStateGetter::PerformSystemButtonPressingIfInFocus, "PerformSystemButtonPressingIfInFocus"},
59 {90, nullptr, "SetPerformanceConfigurationChangedNotification"},
60 {91, nullptr, "GetCurrentPerformanceConfiguration"},
61 {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
62 {110, nullptr, "OpenMyGpuErrorHandler"},
63 {120, &ICommonStateGetter::GetAppletLaunchedHistory, "GetAppletLaunchedHistory"},
64 {200, nullptr, "GetOperationModeSystemInfo"},
65 {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"},
66 {400, nullptr, "ActivateMigrationService"},
67 {401, nullptr, "DeactivateMigrationService"},
68 {500, nullptr, "DisableSleepTillShutdown"},
69 {501, nullptr, "SuppressDisablingSleepTemporarily"},
70 {502, nullptr, "IsSleepEnabled"},
71 {503, nullptr, "IsDisablingSleepSuppressed"},
72 {900, &ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
73 };
74 // clang-format on
75
76 RegisterHandlers(functions);
77}
78
79ICommonStateGetter::~ICommonStateGetter() = default;
80
81void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) {
82 LOG_DEBUG(Service_AM, "called");
83
84 IPC::ResponseBuilder rb{ctx, 3};
85 rb.Push(ResultSuccess);
86 rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
87}
88
89void ICommonStateGetter::GetEventHandle(HLERequestContext& ctx) {
90 LOG_DEBUG(Service_AM, "(STUBBED) called");
91
92 IPC::ResponseBuilder rb{ctx, 2, 1};
93 rb.Push(ResultSuccess);
94 rb.PushCopyObjects(applet->message_queue.GetMessageReceiveEvent());
95}
96
97void ICommonStateGetter::ReceiveMessage(HLERequestContext& ctx) {
98 LOG_DEBUG(Service_AM, "called");
99
100 const auto message = applet->message_queue.PopMessage();
101 IPC::ResponseBuilder rb{ctx, 3};
102
103 if (message == AppletMessageQueue::AppletMessage::None) {
104 LOG_ERROR(Service_AM, "Message queue is empty");
105 rb.Push(AM::ResultNoMessages);
106 rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
107 return;
108 }
109
110 rb.Push(ResultSuccess);
111 rb.PushEnum<AppletMessageQueue::AppletMessage>(message);
112}
113
114void ICommonStateGetter::GetCurrentFocusState(HLERequestContext& ctx) {
115 LOG_DEBUG(Service_AM, "(STUBBED) called");
116
117 std::scoped_lock lk{applet->lock};
118
119 IPC::ResponseBuilder rb{ctx, 3};
120 rb.Push(ResultSuccess);
121 rb.Push(static_cast<u8>(applet->focus_state));
122}
123
124void ICommonStateGetter::GetOperationMode(HLERequestContext& ctx) {
125 const bool use_docked_mode{Settings::IsDockedMode()};
126 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
127
128 IPC::ResponseBuilder rb{ctx, 3};
129 rb.Push(ResultSuccess);
130 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
131}
132
133void ICommonStateGetter::GetPerformanceMode(HLERequestContext& ctx) {
134 LOG_DEBUG(Service_AM, "called");
135
136 IPC::ResponseBuilder rb{ctx, 3};
137 rb.Push(ResultSuccess);
138 rb.PushEnum(system.GetAPMController().GetCurrentPerformanceMode());
139}
140
141void ICommonStateGetter::RequestToAcquireSleepLock(HLERequestContext& ctx) {
142 LOG_WARNING(Service_AM, "(STUBBED) called");
143
144 // Sleep lock is acquired immediately.
145 applet->sleep_lock_event.Signal();
146
147 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(ResultSuccess);
149}
150
151void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
152 IPC::RequestParser rp{ctx};
153 const auto unknown = rp.Pop<u32>();
154
155 LOG_INFO(Service_AM, "called, unknown={}", unknown);
156
157 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
158
159 rb.Push(ResultSuccess);
160 rb.PushIpcInterface<ILockAccessor>(system);
161}
162
163void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
164 LOG_WARNING(Service_AM, "called");
165
166 IPC::ResponseBuilder rb{ctx, 2, 1};
167 rb.Push(ResultSuccess);
168 rb.PushCopyObjects(applet->sleep_lock_event.GetHandle());
169}
170
171void ICommonStateGetter::IsVrModeEnabled(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_AM, "called");
173
174 std::scoped_lock lk{applet->lock};
175
176 IPC::ResponseBuilder rb{ctx, 3};
177 rb.Push(ResultSuccess);
178 rb.Push(applet->vr_mode_enabled);
179}
180
181void ICommonStateGetter::SetVrModeEnabled(HLERequestContext& ctx) {
182 IPC::RequestParser rp{ctx};
183
184 std::scoped_lock lk{applet->lock};
185 applet->vr_mode_enabled = rp.Pop<bool>();
186 LOG_WARNING(Service_AM, "VR Mode is {}", applet->vr_mode_enabled ? "on" : "off");
187
188 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(ResultSuccess);
190}
191
192void ICommonStateGetter::SetLcdBacklighOffEnabled(HLERequestContext& ctx) {
193 IPC::RequestParser rp{ctx};
194 const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
195
196 LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
197 is_lcd_backlight_off_enabled);
198
199 IPC::ResponseBuilder rb{ctx, 2};
200 rb.Push(ResultSuccess);
201}
202
203void ICommonStateGetter::BeginVrModeEx(HLERequestContext& ctx) {
204 LOG_WARNING(Service_AM, "(STUBBED) called");
205
206 std::scoped_lock lk{applet->lock};
207 applet->vr_mode_enabled = true;
208
209 IPC::ResponseBuilder rb{ctx, 2};
210 rb.Push(ResultSuccess);
211}
212
213void ICommonStateGetter::EndVrModeEx(HLERequestContext& ctx) {
214 LOG_WARNING(Service_AM, "(STUBBED) called");
215
216 std::scoped_lock lk{applet->lock};
217 applet->vr_mode_enabled = false;
218
219 IPC::ResponseBuilder rb{ctx, 2};
220 rb.Push(ResultSuccess);
221}
222
223void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx) {
224 LOG_DEBUG(Service_AM, "called");
225
226 IPC::ResponseBuilder rb{ctx, 2, 1};
227 rb.Push(ResultSuccess);
228 rb.PushCopyObjects(applet->message_queue.GetOperationModeChangedEvent());
229}
230
231void ICommonStateGetter::GetDefaultDisplayResolution(HLERequestContext& ctx) {
232 LOG_DEBUG(Service_AM, "called");
233
234 IPC::ResponseBuilder rb{ctx, 4};
235 rb.Push(ResultSuccess);
236
237 if (Settings::IsDockedMode()) {
238 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
239 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
240 } else {
241 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
242 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
243 }
244}
245
246void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
247 LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
248
249 const auto& sm = system.ServiceManager();
250 const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
251 ASSERT(apm_sys != nullptr);
252
253 apm_sys->SetCpuBoostMode(ctx);
254}
255
256void ICommonStateGetter::GetBuiltInDisplayType(HLERequestContext& ctx) {
257 LOG_WARNING(Service_AM, "(STUBBED) called");
258
259 IPC::ResponseBuilder rb{ctx, 3};
260 rb.Push(ResultSuccess);
261 rb.Push(0);
262}
263
264void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx) {
265 IPC::RequestParser rp{ctx};
266 const auto system_button{rp.PopEnum<SystemButtonType>()};
267
268 LOG_WARNING(Service_AM, "(STUBBED) called, system_button={}", system_button);
269
270 IPC::ResponseBuilder rb{ctx, 2};
271 rb.Push(ResultSuccess);
272}
273
274void ICommonStateGetter::GetAppletLaunchedHistory(HLERequestContext& ctx) {
275 LOG_WARNING(Service_AM, "(STUBBED) called");
276
277 std::shared_ptr<Applet> current_applet = applet;
278 std::vector<AppletId> result;
279
280 const size_t count = ctx.GetWriteBufferNumElements<AppletId>();
281 size_t i;
282
283 for (i = 0; i < count && current_applet != nullptr; i++) {
284 result.push_back(current_applet->applet_id);
285 current_applet = current_applet->caller_applet.lock();
286 }
287
288 ctx.WriteBuffer(result);
289
290 IPC::ResponseBuilder rb{ctx, 3};
291 rb.Push(ResultSuccess);
292 rb.Push(static_cast<u32>(i));
293}
294
295void ICommonStateGetter::GetSettingsPlatformRegion(HLERequestContext& ctx) {
296 LOG_WARNING(Service_AM, "(STUBBED) called");
297
298 IPC::ResponseBuilder rb{ctx, 3};
299 rb.Push(ResultSuccess);
300 rb.PushEnum(SysPlatformRegion::Global);
301}
302
303void ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(
304 HLERequestContext& ctx) {
305 LOG_WARNING(Service_AM, "(STUBBED) called");
306
307 std::scoped_lock lk{applet->lock};
308 applet->request_exit_to_library_applet_at_execute_next_program_enabled = true;
309
310 IPC::ResponseBuilder rb{ctx, 2};
311 rb.Push(ResultSuccess);
312}
313
314} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9#include "core/hle/service/am/applet_message_queue.h"
10
11namespace Service::AM {
12
13struct Applet;
14
15class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
16public:
17 explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_);
18 ~ICommonStateGetter() override;
19
20private:
21 // This is nn::oe::FocusState
22 enum class FocusState : u8 {
23 InFocus = 1,
24 NotInFocus = 2,
25 Background = 3,
26 };
27
28 // This is nn::oe::OperationMode
29 enum class OperationMode : u8 {
30 Handheld = 0,
31 Docked = 1,
32 };
33
34 // This is nn::am::service::SystemButtonType
35 enum class SystemButtonType {
36 None,
37 HomeButtonShortPressing,
38 HomeButtonLongPressing,
39 PowerButtonShortPressing,
40 PowerButtonLongPressing,
41 ShutdownSystem,
42 CaptureButtonShortPressing,
43 CaptureButtonLongPressing,
44 };
45
46 enum class SysPlatformRegion : s32 {
47 Global = 1,
48 Terra = 2,
49 };
50
51 void GetEventHandle(HLERequestContext& ctx);
52 void ReceiveMessage(HLERequestContext& ctx);
53 void GetCurrentFocusState(HLERequestContext& ctx);
54 void RequestToAcquireSleepLock(HLERequestContext& ctx);
55 void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
56 void GetReaderLockAccessorEx(HLERequestContext& ctx);
57 void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
58 void GetOperationMode(HLERequestContext& ctx);
59 void GetPerformanceMode(HLERequestContext& ctx);
60 void GetBootMode(HLERequestContext& ctx);
61 void IsVrModeEnabled(HLERequestContext& ctx);
62 void SetVrModeEnabled(HLERequestContext& ctx);
63 void SetLcdBacklighOffEnabled(HLERequestContext& ctx);
64 void BeginVrModeEx(HLERequestContext& ctx);
65 void EndVrModeEx(HLERequestContext& ctx);
66 void GetDefaultDisplayResolution(HLERequestContext& ctx);
67 void SetCpuBoostMode(HLERequestContext& ctx);
68 void GetBuiltInDisplayType(HLERequestContext& ctx);
69 void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
70 void GetAppletLaunchedHistory(HLERequestContext& ctx);
71 void GetSettingsPlatformRegion(HLERequestContext& ctx);
72 void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);
73
74 const std::shared_ptr<Applet> applet;
75};
76
77} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/debug_functions.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IDebugFunctions::IDebugFunctions(Core::System& system_)
10 : ServiceFramework{system_, "IDebugFunctions"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "NotifyMessageToHomeMenuForDebug"},
14 {1, nullptr, "OpenMainApplication"},
15 {10, nullptr, "PerformSystemButtonPressing"},
16 {20, nullptr, "InvalidateTransitionLayer"},
17 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
18 {31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
19 {40, nullptr, "GetAppletResourceUsageInfo"},
20 {50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
21 {51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
22 {100, nullptr, "SetCpuBoostModeForApplet"},
23 {101, nullptr, "CancelCpuBoostModeForApplet"},
24 {110, nullptr, "PushToAppletBoundChannelForDebug"},
25 {111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
26 {120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
27 {121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
28 {122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
29 {130, nullptr, "FriendInvitationSetApplicationParameter"},
30 {131, nullptr, "FriendInvitationClearApplicationParameter"},
31 {132, nullptr, "FriendInvitationPushApplicationParameter"},
32 {140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
33 {200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
34 {300, nullptr, "TerminateAllRunningApplicationsForDebug"},
35 {900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
36 };
37 // clang-format on
38
39 RegisterHandlers(functions);
40}
41
42IDebugFunctions::~IDebugFunctions() = default;
43
44} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
11public:
12 explicit IDebugFunctions(Core::System& system_);
13 ~IDebugFunctions() override;
14};
15
16} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet.h"
5#include "core/hle/service/am/display_controller.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::AM {
9
10namespace {
11struct OutputParameters {
12 bool was_written;
13 s32 fbshare_layer_index;
14};
15
16static_assert(sizeof(OutputParameters) == 8, "OutputParameters has wrong size");
17} // namespace
18
19IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_)
20 : ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, nullptr, "GetLastForegroundCaptureImage"},
24 {1, nullptr, "UpdateLastForegroundCaptureImage"},
25 {2, nullptr, "GetLastApplicationCaptureImage"},
26 {3, nullptr, "GetCallerAppletCaptureImage"},
27 {4, nullptr, "UpdateCallerAppletCaptureImage"},
28 {5, nullptr, "GetLastForegroundCaptureImageEx"},
29 {6, nullptr, "GetLastApplicationCaptureImageEx"},
30 {7, &IDisplayController::GetCallerAppletCaptureImageEx, "GetCallerAppletCaptureImageEx"},
31 {8, &IDisplayController::TakeScreenShotOfOwnLayer, "TakeScreenShotOfOwnLayer"},
32 {9, nullptr, "CopyBetweenCaptureBuffers"},
33 {10, nullptr, "AcquireLastApplicationCaptureBuffer"},
34 {11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
35 {12, nullptr, "AcquireLastForegroundCaptureBuffer"},
36 {13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
37 {14, nullptr, "AcquireCallerAppletCaptureBuffer"},
38 {15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
39 {16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
40 {17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
41 {18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
42 {20, nullptr, "ClearCaptureBuffer"},
43 {21, nullptr, "ClearAppletTransitionBuffer"},
44 {22, &IDisplayController::AcquireLastApplicationCaptureSharedBuffer, "AcquireLastApplicationCaptureSharedBuffer"},
45 {23, &IDisplayController::ReleaseLastApplicationCaptureSharedBuffer, "ReleaseLastApplicationCaptureSharedBuffer"},
46 {24, &IDisplayController::AcquireLastForegroundCaptureSharedBuffer, "AcquireLastForegroundCaptureSharedBuffer"},
47 {25, &IDisplayController::ReleaseLastForegroundCaptureSharedBuffer, "ReleaseLastForegroundCaptureSharedBuffer"},
48 {26, &IDisplayController::AcquireCallerAppletCaptureSharedBuffer, "AcquireCallerAppletCaptureSharedBuffer"},
49 {27, &IDisplayController::ReleaseCallerAppletCaptureSharedBuffer, "ReleaseCallerAppletCaptureSharedBuffer"},
50 {28, nullptr, "TakeScreenShotOfOwnLayerEx"},
51 };
52 // clang-format on
53
54 RegisterHandlers(functions);
55}
56
57IDisplayController::~IDisplayController() = default;
58
59void IDisplayController::GetCallerAppletCaptureImageEx(HLERequestContext& ctx) {
60 LOG_WARNING(Service_AM, "(STUBBED) called");
61
62 OutputParameters params{};
63 const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
64 &params.was_written, &params.fbshare_layer_index);
65
66 IPC::ResponseBuilder rb{ctx, 4};
67 rb.Push(res);
68 rb.PushRaw(params);
69}
70
71void IDisplayController::TakeScreenShotOfOwnLayer(HLERequestContext& ctx) {
72 LOG_WARNING(Service_AM, "(STUBBED) called");
73
74 IPC::ResponseBuilder rb{ctx, 2};
75 rb.Push(ResultSuccess);
76}
77
78void IDisplayController::AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) {
79 LOG_WARNING(Service_AM, "(STUBBED) called");
80
81 OutputParameters params{};
82 const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
83 &params.was_written, &params.fbshare_layer_index);
84
85 IPC::ResponseBuilder rb{ctx, 4};
86 rb.Push(res);
87 rb.PushRaw(params);
88}
89
90void IDisplayController::ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx) {
91 LOG_WARNING(Service_AM, "(STUBBED) called");
92
93 IPC::ResponseBuilder rb{ctx, 2};
94 rb.Push(ResultSuccess);
95}
96
97void IDisplayController::AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
98 LOG_WARNING(Service_AM, "(STUBBED) called");
99
100 OutputParameters params{};
101 const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
102 &params.was_written, &params.fbshare_layer_index);
103
104 IPC::ResponseBuilder rb{ctx, 4};
105 rb.Push(res);
106 rb.PushRaw(params);
107}
108
109void IDisplayController::ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx) {
110 LOG_WARNING(Service_AM, "(STUBBED) called");
111
112 IPC::ResponseBuilder rb{ctx, 2};
113 rb.Push(ResultSuccess);
114}
115
116void IDisplayController::AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
117 LOG_WARNING(Service_AM, "(STUBBED) called");
118
119 OutputParameters params{};
120 const auto res = applet->system_buffer_manager.WriteAppletCaptureBuffer(
121 &params.was_written, &params.fbshare_layer_index);
122
123 IPC::ResponseBuilder rb{ctx, 4};
124 rb.Push(res);
125 rb.PushRaw(params);
126}
127
128void IDisplayController::ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx) {
129 LOG_WARNING(Service_AM, "(STUBBED) called");
130
131 IPC::ResponseBuilder rb{ctx, 2};
132 rb.Push(ResultSuccess);
133}
134
135} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IDisplayController final : public ServiceFramework<IDisplayController> {
13public:
14 explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~IDisplayController() override;
16
17private:
18 void GetCallerAppletCaptureImageEx(HLERequestContext& ctx);
19 void TakeScreenShotOfOwnLayer(HLERequestContext& ctx);
20 void AcquireLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
21 void ReleaseLastForegroundCaptureSharedBuffer(HLERequestContext& ctx);
22 void AcquireCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
23 void ReleaseCallerAppletCaptureSharedBuffer(HLERequestContext& ctx);
24 void AcquireLastApplicationCaptureSharedBuffer(HLERequestContext& ctx);
25 void ReleaseLastApplicationCaptureSharedBuffer(HLERequestContext& ctx);
26
27 const std::shared_ptr<Applet> applet;
28};
29
30} // 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 @@
8#include "core/hle/kernel/k_event.h" 8#include "core/hle/kernel/k_event.h"
9#include "core/hle/kernel/k_readable_event.h" 9#include "core/hle/kernel/k_readable_event.h"
10#include "core/hle/service/am/am.h" 10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/applet_cabinet.h" 11#include "core/hle/service/am/frontend/applet_cabinet.h"
12#include "core/hle/service/am/storage.h"
12#include "core/hle/service/mii/mii_manager.h" 13#include "core/hle/service/mii/mii_manager.h"
13#include "core/hle/service/nfc/common/device.h" 14#include "core/hle/service/nfc/common/device.h"
14#include "hid_core/hid_core.h" 15#include "hid_core/hid_core.h"
15 16
16namespace Service::AM::Applets { 17namespace Service::AM::Frontend {
17 18
18Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, 19Cabinet::Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_,
19 const Core::Frontend::CabinetApplet& frontend_) 20 LibraryAppletMode applet_mode_, const Core::Frontend::CabinetApplet& frontend_)
20 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ 21 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_}, service_context{
21 system_, 22 system_,
22 "CabinetApplet"} { 23 "CabinetApplet"} {
23 24
@@ -30,7 +31,7 @@ Cabinet::~Cabinet() {
30}; 31};
31 32
32void Cabinet::Initialize() { 33void Cabinet::Initialize() {
33 Applet::Initialize(); 34 FrontendApplet::Initialize();
34 35
35 LOG_INFO(Service_HID, "Initializing Cabinet Applet."); 36 LOG_INFO(Service_HID, "Initializing Cabinet Applet.");
36 37
@@ -41,7 +42,7 @@ void Cabinet::Initialize() {
41 common_args.play_startup_sound, common_args.size, common_args.system_tick, 42 common_args.play_startup_sound, common_args.size, common_args.system_tick,
42 common_args.theme_color); 43 common_args.theme_color);
43 44
44 const auto storage = broker.PopNormalDataToApplet(); 45 std::shared_ptr<IStorage> storage = PopInData();
45 ASSERT(storage != nullptr); 46 ASSERT(storage != nullptr);
46 47
47 const auto applet_input_data = storage->GetData(); 48 const auto applet_input_data = storage->GetData();
@@ -51,10 +52,6 @@ void Cabinet::Initialize() {
51 sizeof(StartParamForAmiiboSettings)); 52 sizeof(StartParamForAmiiboSettings));
52} 53}
53 54
54bool Cabinet::TransactionComplete() const {
55 return is_complete;
56}
57
58Result Cabinet::GetStatus() const { 55Result Cabinet::GetStatus() const {
59 return ResultSuccess; 56 return ResultSuccess;
60} 57}
@@ -160,8 +157,8 @@ void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name)
160 157
161 is_complete = true; 158 is_complete = true;
162 159
163 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 160 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
164 broker.SignalStateChanged(); 161 Exit();
165} 162}
166 163
167void Cabinet::Cancel() { 164void Cabinet::Cancel() {
@@ -175,8 +172,8 @@ void Cabinet::Cancel() {
175 172
176 is_complete = true; 173 is_complete = true;
177 174
178 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 175 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
179 broker.SignalStateChanged(); 176 Exit();
180} 177}
181 178
182Result Cabinet::RequestExit() { 179Result Cabinet::RequestExit() {
@@ -184,4 +181,4 @@ Result Cabinet::RequestExit() {
184 R_SUCCEED(); 181 R_SUCCEED();
185} 182}
186 183
187} // namespace Service::AM::Applets 184} // 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 @@
6#include <array> 6#include <array>
7 7
8#include "core/hle/result.h" 8#include "core/hle/result.h"
9#include "core/hle/service/am/applets/applets.h" 9#include "core/hle/service/am/frontend/applets.h"
10#include "core/hle/service/kernel_helpers.h" 10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/nfp/nfp_types.h" 11#include "core/hle/service/nfp/nfp_types.h"
12 12
@@ -23,7 +23,7 @@ namespace Service::NFC {
23class NfcDevice; 23class NfcDevice;
24} 24}
25 25
26namespace Service::AM::Applets { 26namespace Service::AM::Frontend {
27 27
28enum class CabinetAppletVersion : u32 { 28enum class CabinetAppletVersion : u32 {
29 Version1 = 0x1, 29 Version1 = 0x1,
@@ -84,15 +84,15 @@ static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188,
84 "ReturnValueForAmiiboSettings is an invalid size"); 84 "ReturnValueForAmiiboSettings is an invalid size");
85#pragma pack(pop) 85#pragma pack(pop)
86 86
87class Cabinet final : public Applet { 87class Cabinet final : public FrontendApplet {
88public: 88public:
89 explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, 89 explicit Cabinet(Core::System& system_, std::shared_ptr<Applet> applet_,
90 LibraryAppletMode applet_mode_,
90 const Core::Frontend::CabinetApplet& frontend_); 91 const Core::Frontend::CabinetApplet& frontend_);
91 ~Cabinet() override; 92 ~Cabinet() override;
92 93
93 void Initialize() override; 94 void Initialize() override;
94 95
95 bool TransactionComplete() const override;
96 Result GetStatus() const override; 96 Result GetStatus() const override;
97 void ExecuteInteractive() override; 97 void ExecuteInteractive() override;
98 void Execute() override; 98 void Execute() override;
@@ -102,7 +102,6 @@ public:
102 102
103private: 103private:
104 const Core::Frontend::CabinetApplet& frontend; 104 const Core::Frontend::CabinetApplet& frontend;
105 Core::System& system;
106 105
107 bool is_complete{false}; 106 bool is_complete{false};
108 std::shared_ptr<Service::NFC::NfcDevice> nfp_device; 107 std::shared_ptr<Service::NFC::NfcDevice> nfp_device;
@@ -111,4 +110,4 @@ private:
111 StartParamForAmiiboSettings applet_input_common{}; 110 StartParamForAmiiboSettings applet_input_common{};
112}; 111};
113 112
114} // namespace Service::AM::Applets 113} // 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 @@
11#include "core/frontend/applets/controller.h" 11#include "core/frontend/applets/controller.h"
12#include "core/hle/result.h" 12#include "core/hle/result.h"
13#include "core/hle/service/am/am.h" 13#include "core/hle/service/am/am.h"
14#include "core/hle/service/am/applets/applet_controller.h" 14#include "core/hle/service/am/frontend/applet_controller.h"
15#include "core/hle/service/am/storage.h"
15#include "hid_core/frontend/emulated_controller.h" 16#include "hid_core/frontend/emulated_controller.h"
16#include "hid_core/hid_core.h" 17#include "hid_core/hid_core.h"
17#include "hid_core/hid_types.h" 18#include "hid_core/hid_types.h"
18#include "hid_core/resources/npad/npad.h" 19#include "hid_core/resources/npad/npad.h"
19 20
20namespace Service::AM::Applets { 21namespace Service::AM::Frontend {
21 22
22[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101}; 23[[maybe_unused]] constexpr Result ResultControllerSupportCanceled{ErrorModule::HID, 3101};
23[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID, 24[[maybe_unused]] constexpr Result ResultControllerSupportNotSupportedNpadStyle{ErrorModule::HID,
@@ -46,14 +47,15 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
46 }; 47 };
47} 48}
48 49
49Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_, 50Controller::Controller(Core::System& system_, std::shared_ptr<Applet> applet_,
51 LibraryAppletMode applet_mode_,
50 const Core::Frontend::ControllerApplet& frontend_) 52 const Core::Frontend::ControllerApplet& frontend_)
51 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 53 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
52 54
53Controller::~Controller() = default; 55Controller::~Controller() = default;
54 56
55void Controller::Initialize() { 57void Controller::Initialize() {
56 Applet::Initialize(); 58 FrontendApplet::Initialize();
57 59
58 LOG_INFO(Service_HID, "Initializing Controller Applet."); 60 LOG_INFO(Service_HID, "Initializing Controller Applet.");
59 61
@@ -66,7 +68,7 @@ void Controller::Initialize() {
66 68
67 controller_applet_version = ControllerAppletVersion{common_args.library_version}; 69 controller_applet_version = ControllerAppletVersion{common_args.library_version};
68 70
69 const auto private_arg_storage = broker.PopNormalDataToApplet(); 71 const std::shared_ptr<IStorage> private_arg_storage = PopInData();
70 ASSERT(private_arg_storage != nullptr); 72 ASSERT(private_arg_storage != nullptr);
71 73
72 const auto& private_arg = private_arg_storage->GetData(); 74 const auto& private_arg = private_arg_storage->GetData();
@@ -116,7 +118,7 @@ void Controller::Initialize() {
116 switch (controller_private_arg.mode) { 118 switch (controller_private_arg.mode) {
117 case ControllerSupportMode::ShowControllerSupport: 119 case ControllerSupportMode::ShowControllerSupport:
118 case ControllerSupportMode::ShowControllerStrapGuide: { 120 case ControllerSupportMode::ShowControllerStrapGuide: {
119 const auto user_arg_storage = broker.PopNormalDataToApplet(); 121 const std::shared_ptr<IStorage> user_arg_storage = PopInData();
120 ASSERT(user_arg_storage != nullptr); 122 ASSERT(user_arg_storage != nullptr);
121 123
122 const auto& user_arg = user_arg_storage->GetData(); 124 const auto& user_arg = user_arg_storage->GetData();
@@ -142,7 +144,7 @@ void Controller::Initialize() {
142 break; 144 break;
143 } 145 }
144 case ControllerSupportMode::ShowControllerFirmwareUpdate: { 146 case ControllerSupportMode::ShowControllerFirmwareUpdate: {
145 const auto update_arg_storage = broker.PopNormalDataToApplet(); 147 const std::shared_ptr<IStorage> update_arg_storage = PopInData();
146 ASSERT(update_arg_storage != nullptr); 148 ASSERT(update_arg_storage != nullptr);
147 149
148 const auto& update_arg = update_arg_storage->GetData(); 150 const auto& update_arg = update_arg_storage->GetData();
@@ -152,7 +154,7 @@ void Controller::Initialize() {
152 break; 154 break;
153 } 155 }
154 case ControllerSupportMode::ShowControllerKeyRemappingForSystem: { 156 case ControllerSupportMode::ShowControllerKeyRemappingForSystem: {
155 const auto remapping_arg_storage = broker.PopNormalDataToApplet(); 157 const std::shared_ptr<IStorage> remapping_arg_storage = PopInData();
156 ASSERT(remapping_arg_storage != nullptr); 158 ASSERT(remapping_arg_storage != nullptr);
157 159
158 const auto& remapping_arg = remapping_arg_storage->GetData(); 160 const auto& remapping_arg = remapping_arg_storage->GetData();
@@ -168,10 +170,6 @@ void Controller::Initialize() {
168 } 170 }
169} 171}
170 172
171bool Controller::TransactionComplete() const {
172 return complete;
173}
174
175Result Controller::GetStatus() const { 173Result Controller::GetStatus() const {
176 return status; 174 return status;
177} 175}
@@ -260,8 +258,9 @@ void Controller::ConfigurationComplete(bool is_success) {
260 complete = true; 258 complete = true;
261 out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo)); 259 out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
262 std::memcpy(out_data.data(), &result_info, out_data.size()); 260 std::memcpy(out_data.data(), &result_info, out_data.size());
263 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 261
264 broker.SignalStateChanged(); 262 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
263 Exit();
265} 264}
266 265
267Result Controller::RequestExit() { 266Result Controller::RequestExit() {
@@ -269,4 +268,4 @@ Result Controller::RequestExit() {
269 R_SUCCEED(); 268 R_SUCCEED();
270} 269}
271 270
272} // namespace Service::AM::Applets 271} // 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 @@
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12#include "core/hle/service/am/applets/applets.h" 12#include "core/hle/service/am/frontend/applets.h"
13 13
14namespace Core { 14namespace Core {
15class System; 15class System;
@@ -19,7 +19,7 @@ namespace Core::HID {
19enum class NpadStyleSet : u32; 19enum class NpadStyleSet : u32;
20} 20}
21 21
22namespace Service::AM::Applets { 22namespace Service::AM::Frontend {
23 23
24using IdentificationColor = std::array<u8, 4>; 24using IdentificationColor = std::array<u8, 4>;
25using ExplainText = std::array<char, 0x81>; 25using ExplainText = std::array<char, 0x81>;
@@ -122,15 +122,15 @@ struct ControllerSupportResultInfo {
122static_assert(sizeof(ControllerSupportResultInfo) == 0xC, 122static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
123 "ControllerSupportResultInfo has incorrect size."); 123 "ControllerSupportResultInfo has incorrect size.");
124 124
125class Controller final : public Applet { 125class Controller final : public FrontendApplet {
126public: 126public:
127 explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_, 127 explicit Controller(Core::System& system_, std::shared_ptr<Applet> applet_,
128 LibraryAppletMode applet_mode_,
128 const Core::Frontend::ControllerApplet& frontend_); 129 const Core::Frontend::ControllerApplet& frontend_);
129 ~Controller() override; 130 ~Controller() override;
130 131
131 void Initialize() override; 132 void Initialize() override;
132 133
133 bool TransactionComplete() const override;
134 Result GetStatus() const override; 134 Result GetStatus() const override;
135 void ExecuteInteractive() override; 135 void ExecuteInteractive() override;
136 void Execute() override; 136 void Execute() override;
@@ -140,7 +140,6 @@ public:
140 140
141private: 141private:
142 const Core::Frontend::ControllerApplet& frontend; 142 const Core::Frontend::ControllerApplet& frontend;
143 Core::System& system;
144 143
145 ControllerAppletVersion controller_applet_version; 144 ControllerAppletVersion controller_applet_version;
146 ControllerSupportArgPrivate controller_private_arg; 145 ControllerSupportArgPrivate controller_private_arg;
@@ -154,4 +153,4 @@ private:
154 std::vector<u8> out_data; 153 std::vector<u8> out_data;
155}; 154};
156 155
157} // namespace Service::AM::Applets 156} // 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 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/frontend/applets/error.h" 10#include "core/frontend/applets/error.h"
11#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applet_error.h" 12#include "core/hle/service/am/frontend/applet_error.h"
13#include "core/hle/service/am/storage.h"
13#include "core/reporter.h" 14#include "core/reporter.h"
14 15
15namespace Service::AM::Applets { 16namespace Service::AM::Frontend {
16 17
17struct ErrorCode { 18struct ErrorCode {
18 u32 error_category{}; 19 u32 error_category{};
@@ -103,18 +104,18 @@ Result Decode64BitError(u64 error) {
103 104
104} // Anonymous namespace 105} // Anonymous namespace
105 106
106Error::Error(Core::System& system_, LibraryAppletMode applet_mode_, 107Error::Error(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_,
107 const Core::Frontend::ErrorApplet& frontend_) 108 const Core::Frontend::ErrorApplet& frontend_)
108 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 109 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
109 110
110Error::~Error() = default; 111Error::~Error() = default;
111 112
112void Error::Initialize() { 113void Error::Initialize() {
113 Applet::Initialize(); 114 FrontendApplet::Initialize();
114 args = std::make_unique<ErrorArguments>(); 115 args = std::make_unique<ErrorArguments>();
115 complete = false; 116 complete = false;
116 117
117 const auto storage = broker.PopNormalDataToApplet(); 118 const std::shared_ptr<IStorage> storage = PopInData();
118 ASSERT(storage != nullptr); 119 ASSERT(storage != nullptr);
119 const auto data = storage->GetData(); 120 const auto data = storage->GetData();
120 121
@@ -152,10 +153,6 @@ void Error::Initialize() {
152 } 153 }
153} 154}
154 155
155bool Error::TransactionComplete() const {
156 return complete;
157}
158
159Result Error::GetStatus() const { 156Result Error::GetStatus() const {
160 return ResultSuccess; 157 return ResultSuccess;
161} 158}
@@ -210,8 +207,8 @@ void Error::Execute() {
210 207
211void Error::DisplayCompleted() { 208void Error::DisplayCompleted() {
212 complete = true; 209 complete = true;
213 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); 210 PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
214 broker.SignalStateChanged(); 211 Exit();
215} 212}
216 213
217Result Error::RequestExit() { 214Result Error::RequestExit() {
@@ -219,4 +216,4 @@ Result Error::RequestExit() {
219 R_SUCCEED(); 216 R_SUCCEED();
220} 217}
221 218
222} // namespace Service::AM::Applets 219} // 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 @@
4#pragma once 4#pragma once
5 5
6#include "core/hle/result.h" 6#include "core/hle/result.h"
7#include "core/hle/service/am/applets/applets.h" 7#include "core/hle/service/am/frontend/applets.h"
8 8
9namespace Core { 9namespace Core {
10class System; 10class System;
11} 11}
12 12
13namespace Service::AM::Applets { 13namespace Service::AM::Frontend {
14 14
15enum class ErrorAppletMode : u8 { 15enum class ErrorAppletMode : u8 {
16 ShowError = 0, 16 ShowError = 0,
@@ -22,15 +22,14 @@ enum class ErrorAppletMode : u8 {
22 ShowUpdateEula = 8, 22 ShowUpdateEula = 8,
23}; 23};
24 24
25class Error final : public Applet { 25class Error final : public FrontendApplet {
26public: 26public:
27 explicit Error(Core::System& system_, LibraryAppletMode applet_mode_, 27 explicit Error(Core::System& system_, std::shared_ptr<Applet> applet_,
28 const Core::Frontend::ErrorApplet& frontend_); 28 LibraryAppletMode applet_mode_, const Core::Frontend::ErrorApplet& frontend_);
29 ~Error() override; 29 ~Error() override;
30 30
31 void Initialize() override; 31 void Initialize() override;
32 32
33 bool TransactionComplete() const override;
34 Result GetStatus() const override; 33 Result GetStatus() const override;
35 void ExecuteInteractive() override; 34 void ExecuteInteractive() override;
36 void Execute() override; 35 void Execute() override;
@@ -47,7 +46,6 @@ private:
47 std::unique_ptr<ErrorArguments> args; 46 std::unique_ptr<ErrorArguments> args;
48 47
49 bool complete = false; 48 bool complete = false;
50 Core::System& system;
51}; 49};
52 50
53} // namespace Service::AM::Applets 51} // 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 @@
5#include "common/hex_util.h" 5#include "common/hex_util.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/frontend/applets/general_frontend.h" 8#include "core/frontend/applets/general.h"
9#include "core/hle/result.h" 9#include "core/hle/result.h"
10#include "core/hle/service/am/am.h" 10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/applet_general_backend.h" 11#include "core/hle/service/am/applet_data_broker.h"
12#include "core/hle/service/am/frontend/applet_general.h"
13#include "core/hle/service/am/storage.h"
12#include "core/reporter.h" 14#include "core/reporter.h"
13 15
14namespace Service::AM::Applets { 16namespace Service::AM::Frontend {
15 17
16constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221}; 18constexpr Result ERROR_INVALID_PIN{ErrorModule::PCTL, 221};
17 19
18static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix) { 20static void LogCurrentStorage(std::shared_ptr<Applet> applet, std::string_view prefix) {
19 std::shared_ptr<IStorage> storage = broker.PopNormalDataToApplet(); 21 std::shared_ptr<IStorage> storage;
20 for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { 22 while (R_SUCCEEDED(applet->caller_applet_broker->GetInData().Pop(&storage))) {
21 const auto data = storage->GetData(); 23 const auto data = storage->GetData();
22 LOG_INFO(Service_AM, 24 LOG_INFO(Service_AM,
23 "called (STUBBED), during {} received normal data with size={:08X}, data={}", 25 "called (STUBBED), during {} received normal data with size={:08X}, data={}",
24 prefix, data.size(), Common::HexToString(data)); 26 prefix, data.size(), Common::HexToString(data));
25 } 27 }
26 28
27 storage = broker.PopInteractiveDataToApplet(); 29 while (R_SUCCEEDED(applet->caller_applet_broker->GetInteractiveInData().Pop(&storage))) {
28 for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
29 const auto data = storage->GetData(); 30 const auto data = storage->GetData();
30 LOG_INFO(Service_AM, 31 LOG_INFO(Service_AM,
31 "called (STUBBED), during {} received interactive data with size={:08X}, data={}", 32 "called (STUBBED), during {} received interactive data with size={:08X}, data={}",
@@ -33,17 +34,17 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
33 } 34 }
34} 35}
35 36
36Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_, 37Auth::Auth(Core::System& system_, std::shared_ptr<Applet> applet_, LibraryAppletMode applet_mode_,
37 Core::Frontend::ParentalControlsApplet& frontend_) 38 Core::Frontend::ParentalControlsApplet& frontend_)
38 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 39 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
39 40
40Auth::~Auth() = default; 41Auth::~Auth() = default;
41 42
42void Auth::Initialize() { 43void Auth::Initialize() {
43 Applet::Initialize(); 44 FrontendApplet::Initialize();
44 complete = false; 45 complete = false;
45 46
46 const auto storage = broker.PopNormalDataToApplet(); 47 const std::shared_ptr<IStorage> storage = PopInData();
47 ASSERT(storage != nullptr); 48 ASSERT(storage != nullptr);
48 const auto data = storage->GetData(); 49 const auto data = storage->GetData();
49 ASSERT(data.size() >= 0xC); 50 ASSERT(data.size() >= 0xC);
@@ -67,10 +68,6 @@ void Auth::Initialize() {
67 arg2 = arg.arg2; 68 arg2 = arg.arg2;
68} 69}
69 70
70bool Auth::TransactionComplete() const {
71 return complete;
72}
73
74Result Auth::GetStatus() const { 71Result Auth::GetStatus() const {
75 return successful ? ResultSuccess : ERROR_INVALID_PIN; 72 return successful ? ResultSuccess : ERROR_INVALID_PIN;
76} 73}
@@ -146,8 +143,8 @@ void Auth::AuthFinished(bool is_successful) {
146 std::vector<u8> out(sizeof(Return)); 143 std::vector<u8> out(sizeof(Return));
147 std::memcpy(out.data(), &return_, sizeof(Return)); 144 std::memcpy(out.data(), &return_, sizeof(Return));
148 145
149 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out))); 146 PushOutData(std::make_shared<IStorage>(system, std::move(out)));
150 broker.SignalStateChanged(); 147 Exit();
151} 148}
152 149
153Result Auth::RequestExit() { 150Result Auth::RequestExit() {
@@ -155,27 +152,24 @@ Result Auth::RequestExit() {
155 R_SUCCEED(); 152 R_SUCCEED();
156} 153}
157 154
158PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, 155PhotoViewer::PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_,
156 LibraryAppletMode applet_mode_,
159 const Core::Frontend::PhotoViewerApplet& frontend_) 157 const Core::Frontend::PhotoViewerApplet& frontend_)
160 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 158 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
161 159
162PhotoViewer::~PhotoViewer() = default; 160PhotoViewer::~PhotoViewer() = default;
163 161
164void PhotoViewer::Initialize() { 162void PhotoViewer::Initialize() {
165 Applet::Initialize(); 163 FrontendApplet::Initialize();
166 complete = false; 164 complete = false;
167 165
168 const auto storage = broker.PopNormalDataToApplet(); 166 const std::shared_ptr<IStorage> storage = PopInData();
169 ASSERT(storage != nullptr); 167 ASSERT(storage != nullptr);
170 const auto data = storage->GetData(); 168 const auto data = storage->GetData();
171 ASSERT(!data.empty()); 169 ASSERT(!data.empty());
172 mode = static_cast<PhotoViewerAppletMode>(data[0]); 170 mode = static_cast<PhotoViewerAppletMode>(data[0]);
173} 171}
174 172
175bool PhotoViewer::TransactionComplete() const {
176 return complete;
177}
178
179Result PhotoViewer::GetStatus() const { 173Result PhotoViewer::GetStatus() const {
180 return ResultSuccess; 174 return ResultSuccess;
181} 175}
@@ -203,8 +197,8 @@ void PhotoViewer::Execute() {
203} 197}
204 198
205void PhotoViewer::ViewFinished() { 199void PhotoViewer::ViewFinished() {
206 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>{})); 200 PushOutData(std::make_shared<IStorage>(system, std::vector<u8>{}));
207 broker.SignalStateChanged(); 201 Exit();
208} 202}
209 203
210Result PhotoViewer::RequestExit() { 204Result PhotoViewer::RequestExit() {
@@ -212,27 +206,17 @@ Result PhotoViewer::RequestExit() {
212 R_SUCCEED(); 206 R_SUCCEED();
213} 207}
214 208
215StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_) 209StubApplet::StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_,
216 : Applet{system_, applet_mode_}, id{id_}, system{system_} {} 210 LibraryAppletMode applet_mode_)
211 : FrontendApplet{system_, applet_, applet_mode_}, id{id_} {}
217 212
218StubApplet::~StubApplet() = default; 213StubApplet::~StubApplet() = default;
219 214
220void StubApplet::Initialize() { 215void StubApplet::Initialize() {
221 LOG_WARNING(Service_AM, "called (STUBBED)"); 216 LOG_WARNING(Service_AM, "called (STUBBED)");
222 Applet::Initialize(); 217 FrontendApplet::Initialize();
223 218
224 const auto data = broker.PeekDataToAppletForDebug(); 219 LogCurrentStorage(applet.lock(), "Initialize");
225 system.GetReporter().SaveUnimplementedAppletReport(
226 static_cast<u32>(id), static_cast<u32>(common_args.arguments_version),
227 common_args.library_version, static_cast<u32>(common_args.theme_color),
228 common_args.play_startup_sound, common_args.system_tick, data.normal, data.interactive);
229
230 LogCurrentStorage(broker, "Initialize");
231}
232
233bool StubApplet::TransactionComplete() const {
234 LOG_WARNING(Service_AM, "called (STUBBED)");
235 return true;
236} 220}
237 221
238Result StubApplet::GetStatus() const { 222Result StubApplet::GetStatus() const {
@@ -242,22 +226,20 @@ Result StubApplet::GetStatus() const {
242 226
243void StubApplet::ExecuteInteractive() { 227void StubApplet::ExecuteInteractive() {
244 LOG_WARNING(Service_AM, "called (STUBBED)"); 228 LOG_WARNING(Service_AM, "called (STUBBED)");
245 LogCurrentStorage(broker, "ExecuteInteractive"); 229 LogCurrentStorage(applet.lock(), "ExecuteInteractive");
246 230
247 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); 231 PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
248 broker.PushInteractiveDataFromApplet( 232 PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
249 std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); 233 Exit();
250 broker.SignalStateChanged();
251} 234}
252 235
253void StubApplet::Execute() { 236void StubApplet::Execute() {
254 LOG_WARNING(Service_AM, "called (STUBBED)"); 237 LOG_WARNING(Service_AM, "called (STUBBED)");
255 LogCurrentStorage(broker, "Execute"); 238 LogCurrentStorage(applet.lock(), "Execute");
256 239
257 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); 240 PushOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
258 broker.PushInteractiveDataFromApplet( 241 PushInteractiveOutData(std::make_shared<IStorage>(system, std::vector<u8>(0x1000)));
259 std::make_shared<IStorage>(system, std::vector<u8>(0x1000))); 242 Exit();
260 broker.SignalStateChanged();
261} 243}
262 244
263Result StubApplet::RequestExit() { 245Result StubApplet::RequestExit() {
@@ -265,4 +247,4 @@ Result StubApplet::RequestExit() {
265 R_SUCCEED(); 247 R_SUCCEED();
266} 248}
267 249
268} // namespace Service::AM::Applets 250} // 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 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/am/applets/applets.h" 6#include "core/hle/service/am/frontend/applets.h"
7 7
8namespace Core { 8namespace Core {
9class System; 9class System;
10} 10}
11 11
12namespace Service::AM::Applets { 12namespace Service::AM::Frontend {
13 13
14enum class AuthAppletType : u32 { 14enum class AuthAppletType : u32 {
15 ShowParentalAuthentication, 15 ShowParentalAuthentication,
@@ -17,14 +17,14 @@ enum class AuthAppletType : u32 {
17 ChangeParentalPasscode, 17 ChangeParentalPasscode,
18}; 18};
19 19
20class Auth final : public Applet { 20class Auth final : public FrontendApplet {
21public: 21public:
22 explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_, 22 explicit Auth(Core::System& system_, std::shared_ptr<Applet> applet_,
23 LibraryAppletMode applet_mode_,
23 Core::Frontend::ParentalControlsApplet& frontend_); 24 Core::Frontend::ParentalControlsApplet& frontend_);
24 ~Auth() override; 25 ~Auth() override;
25 26
26 void Initialize() override; 27 void Initialize() override;
27 bool TransactionComplete() const override;
28 Result GetStatus() const override; 28 Result GetStatus() const override;
29 void ExecuteInteractive() override; 29 void ExecuteInteractive() override;
30 void Execute() override; 30 void Execute() override;
@@ -34,7 +34,6 @@ public:
34 34
35private: 35private:
36 Core::Frontend::ParentalControlsApplet& frontend; 36 Core::Frontend::ParentalControlsApplet& frontend;
37 Core::System& system;
38 bool complete = false; 37 bool complete = false;
39 bool successful = false; 38 bool successful = false;
40 39
@@ -49,14 +48,14 @@ enum class PhotoViewerAppletMode : u8 {
49 AllApps = 1, 48 AllApps = 1,
50}; 49};
51 50
52class PhotoViewer final : public Applet { 51class PhotoViewer final : public FrontendApplet {
53public: 52public:
54 explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_, 53 explicit PhotoViewer(Core::System& system_, std::shared_ptr<Applet> applet_,
54 LibraryAppletMode applet_mode_,
55 const Core::Frontend::PhotoViewerApplet& frontend_); 55 const Core::Frontend::PhotoViewerApplet& frontend_);
56 ~PhotoViewer() override; 56 ~PhotoViewer() override;
57 57
58 void Initialize() override; 58 void Initialize() override;
59 bool TransactionComplete() const override;
60 Result GetStatus() const override; 59 Result GetStatus() const override;
61 void ExecuteInteractive() override; 60 void ExecuteInteractive() override;
62 void Execute() override; 61 void Execute() override;
@@ -68,17 +67,16 @@ private:
68 const Core::Frontend::PhotoViewerApplet& frontend; 67 const Core::Frontend::PhotoViewerApplet& frontend;
69 bool complete = false; 68 bool complete = false;
70 PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; 69 PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
71 Core::System& system;
72}; 70};
73 71
74class StubApplet final : public Applet { 72class StubApplet final : public FrontendApplet {
75public: 73public:
76 explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_); 74 explicit StubApplet(Core::System& system_, std::shared_ptr<Applet> applet_, AppletId id_,
75 LibraryAppletMode applet_mode_);
77 ~StubApplet() override; 76 ~StubApplet() override;
78 77
79 void Initialize() override; 78 void Initialize() override;
80 79
81 bool TransactionComplete() const override;
82 Result GetStatus() const override; 80 Result GetStatus() const override;
83 void ExecuteInteractive() override; 81 void ExecuteInteractive() override;
84 void Execute() override; 82 void Execute() override;
@@ -86,7 +84,6 @@ public:
86 84
87private: 85private:
88 AppletId id; 86 AppletId id;
89 Core::System& system;
90}; 87};
91 88
92} // namespace Service::AM::Applets 89} // 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 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "core/frontend/applets/mii_edit.h" 7#include "core/frontend/applets/mii_edit.h"
8#include "core/hle/service/am/am.h" 8#include "core/hle/service/am/am.h"
9#include "core/hle/service/am/applets/applet_mii_edit.h" 9#include "core/hle/service/am/frontend/applet_mii_edit.h"
10#include "core/hle/service/am/storage.h"
10#include "core/hle/service/mii/mii.h" 11#include "core/hle/service/mii/mii.h"
11#include "core/hle/service/mii/mii_manager.h" 12#include "core/hle/service/mii/mii_manager.h"
12#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
13 14
14namespace Service::AM::Applets { 15namespace Service::AM::Frontend {
15 16
16MiiEdit::MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, 17MiiEdit::MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_,
17 const Core::Frontend::MiiEditApplet& frontend_) 18 LibraryAppletMode applet_mode_, const Core::Frontend::MiiEditApplet& frontend_)
18 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 19 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
19 20
20MiiEdit::~MiiEdit() = default; 21MiiEdit::~MiiEdit() = default;
21 22
@@ -24,7 +25,7 @@ void MiiEdit::Initialize() {
24 // Instead, it is initialized by an AppletInput storage with size 0x100 bytes. 25 // Instead, it is initialized by an AppletInput storage with size 0x100 bytes.
25 // Do NOT call Applet::Initialize() here. 26 // Do NOT call Applet::Initialize() here.
26 27
27 const auto storage = broker.PopNormalDataToApplet(); 28 const std::shared_ptr<IStorage> storage = PopInData();
28 ASSERT(storage != nullptr); 29 ASSERT(storage != nullptr);
29 30
30 const auto applet_input_data = storage->GetData(); 31 const auto applet_input_data = storage->GetData();
@@ -66,10 +67,6 @@ void MiiEdit::Initialize() {
66 manager->Initialize(metadata); 67 manager->Initialize(metadata);
67} 68}
68 69
69bool MiiEdit::TransactionComplete() const {
70 return is_complete;
71}
72
73Result MiiEdit::GetStatus() const { 70Result MiiEdit::GetStatus() const {
74 return ResultSuccess; 71 return ResultSuccess;
75} 72}
@@ -152,8 +149,8 @@ void MiiEdit::MiiEditOutput(MiiEditResult result, s32 index) {
152 149
153 is_complete = true; 150 is_complete = true;
154 151
155 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 152 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
156 broker.SignalStateChanged(); 153 Exit();
157} 154}
158 155
159void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result, 156void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
@@ -168,8 +165,8 @@ void MiiEdit::MiiEditOutputForCharInfoEditing(MiiEditResult result,
168 165
169 is_complete = true; 166 is_complete = true;
170 167
171 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 168 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
172 broker.SignalStateChanged(); 169 Exit();
173} 170}
174 171
175Result MiiEdit::RequestExit() { 172Result MiiEdit::RequestExit() {
@@ -177,4 +174,4 @@ Result MiiEdit::RequestExit() {
177 R_SUCCEED(); 174 R_SUCCEED();
178} 175}
179 176
180} // namespace Service::AM::Applets 177} // 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 @@
4#pragma once 4#pragma once
5 5
6#include "core/hle/result.h" 6#include "core/hle/result.h"
7#include "core/hle/service/am/applets/applet_mii_edit_types.h" 7#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
8#include "core/hle/service/am/applets/applets.h" 8#include "core/hle/service/am/frontend/applets.h"
9 9
10namespace Core { 10namespace Core {
11class System; 11class System;
@@ -16,17 +16,17 @@ struct DatabaseSessionMetadata;
16class MiiManager; 16class MiiManager;
17} // namespace Service::Mii 17} // namespace Service::Mii
18 18
19namespace Service::AM::Applets { 19namespace Service::AM::Frontend {
20 20
21class MiiEdit final : public Applet { 21class MiiEdit final : public FrontendApplet {
22public: 22public:
23 explicit MiiEdit(Core::System& system_, LibraryAppletMode applet_mode_, 23 explicit MiiEdit(Core::System& system_, std::shared_ptr<Applet> applet_,
24 LibraryAppletMode applet_mode_,
24 const Core::Frontend::MiiEditApplet& frontend_); 25 const Core::Frontend::MiiEditApplet& frontend_);
25 ~MiiEdit() override; 26 ~MiiEdit() override;
26 27
27 void Initialize() override; 28 void Initialize() override;
28 29
29 bool TransactionComplete() const override;
30 Result GetStatus() const override; 30 Result GetStatus() const override;
31 void ExecuteInteractive() override; 31 void ExecuteInteractive() override;
32 void Execute() override; 32 void Execute() override;
@@ -38,7 +38,6 @@ public:
38 38
39private: 39private:
40 const Core::Frontend::MiiEditApplet& frontend; 40 const Core::Frontend::MiiEditApplet& frontend;
41 Core::System& system;
42 41
43 MiiEditAppletInputCommon applet_input_common{}; 42 MiiEditAppletInputCommon applet_input_common{};
44 MiiEditAppletInputV3 applet_input_v3{}; 43 MiiEditAppletInputV3 applet_input_v3{};
@@ -49,4 +48,4 @@ private:
49 Mii::DatabaseSessionMetadata metadata{}; 48 Mii::DatabaseSessionMetadata metadata{};
50}; 49};
51 50
52} // namespace Service::AM::Applets 51} // 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 @@
10#include "common/uuid.h" 10#include "common/uuid.h"
11#include "core/hle/service/mii/types/char_info.h" 11#include "core/hle/service/mii/types/char_info.h"
12 12
13namespace Service::AM::Applets { 13namespace Service::AM::Frontend {
14 14
15enum class MiiEditAppletVersion : s32 { 15enum class MiiEditAppletVersion : s32 {
16 Version3 = 0x3, // 1.0.0 - 10.1.1 16 Version3 = 0x3, // 1.0.0 - 10.1.1
@@ -80,4 +80,4 @@ struct MiiEditAppletOutputForCharInfoEditing {
80static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80, 80static_assert(sizeof(MiiEditAppletOutputForCharInfoEditing) == 0x80,
81 "MiiEditAppletOutputForCharInfoEditing has incorrect size."); 81 "MiiEditAppletOutputForCharInfoEditing has incorrect size.");
82 82
83} // namespace Service::AM::Applets 83} // 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 @@
9#include "core/frontend/applets/profile_select.h" 9#include "core/frontend/applets/profile_select.h"
10#include "core/hle/service/acc/errors.h" 10#include "core/hle/service/acc/errors.h"
11#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applet_profile_select.h" 12#include "core/hle/service/am/frontend/applet_profile_select.h"
13#include "core/hle/service/am/storage.h"
13 14
14namespace Service::AM::Applets { 15namespace Service::AM::Frontend {
15 16
16ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, 17ProfileSelect::ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_,
18 LibraryAppletMode applet_mode_,
17 const Core::Frontend::ProfileSelectApplet& frontend_) 19 const Core::Frontend::ProfileSelectApplet& frontend_)
18 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 20 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
19 21
20ProfileSelect::~ProfileSelect() = default; 22ProfileSelect::~ProfileSelect() = default;
21 23
@@ -24,10 +26,10 @@ void ProfileSelect::Initialize() {
24 status = ResultSuccess; 26 status = ResultSuccess;
25 final_data.clear(); 27 final_data.clear();
26 28
27 Applet::Initialize(); 29 FrontendApplet::Initialize();
28 profile_select_version = ProfileSelectAppletVersion{common_args.library_version}; 30 profile_select_version = ProfileSelectAppletVersion{common_args.library_version};
29 31
30 const auto user_config_storage = broker.PopNormalDataToApplet(); 32 const std::shared_ptr<IStorage> user_config_storage = PopInData();
31 ASSERT(user_config_storage != nullptr); 33 ASSERT(user_config_storage != nullptr);
32 const auto& user_config = user_config_storage->GetData(); 34 const auto& user_config = user_config_storage->GetData();
33 35
@@ -50,10 +52,6 @@ void ProfileSelect::Initialize() {
50 } 52 }
51} 53}
52 54
53bool ProfileSelect::TransactionComplete() const {
54 return complete;
55}
56
57Result ProfileSelect::GetStatus() const { 55Result ProfileSelect::GetStatus() const {
58 return status; 56 return status;
59} 57}
@@ -64,7 +62,8 @@ void ProfileSelect::ExecuteInteractive() {
64 62
65void ProfileSelect::Execute() { 63void ProfileSelect::Execute() {
66 if (complete) { 64 if (complete) {
67 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); 65 PushOutData(std::make_shared<IStorage>(system, std::move(final_data)));
66 Exit();
68 return; 67 return;
69 } 68 }
70 69
@@ -111,8 +110,9 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
111 110
112 final_data = std::vector<u8>(sizeof(UiReturnArg)); 111 final_data = std::vector<u8>(sizeof(UiReturnArg));
113 std::memcpy(final_data.data(), &output, final_data.size()); 112 std::memcpy(final_data.data(), &output, final_data.size());
114 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(final_data))); 113
115 broker.SignalStateChanged(); 114 PushOutData(std::make_shared<IStorage>(system, std::move(final_data)));
115 Exit();
116} 116}
117 117
118Result ProfileSelect::RequestExit() { 118Result ProfileSelect::RequestExit() {
@@ -120,4 +120,4 @@ Result ProfileSelect::RequestExit() {
120 R_SUCCEED(); 120 R_SUCCEED();
121} 121}
122 122
123} // namespace Service::AM::Applets 123} // 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 @@
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/uuid.h" 9#include "common/uuid.h"
10#include "core/hle/result.h" 10#include "core/hle/result.h"
11#include "core/hle/service/am/applets/applets.h" 11#include "core/hle/service/am/frontend/applets.h"
12 12
13namespace Core { 13namespace Core {
14class System; 14class System;
15} 15}
16 16
17namespace Service::AM::Applets { 17namespace Service::AM::Frontend {
18 18
19enum class ProfileSelectAppletVersion : u32 { 19enum class ProfileSelectAppletVersion : u32 {
20 Version1 = 0x1, // 1.0.0+ 20 Version1 = 0x1, // 1.0.0+
@@ -111,15 +111,15 @@ struct UiReturnArg {
111}; 111};
112static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size."); 112static_assert(sizeof(UiReturnArg) == 0x18, "UiReturnArg has incorrect size.");
113 113
114class ProfileSelect final : public Applet { 114class ProfileSelect final : public FrontendApplet {
115public: 115public:
116 explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_, 116 explicit ProfileSelect(Core::System& system_, std::shared_ptr<Applet> applet_,
117 LibraryAppletMode applet_mode_,
117 const Core::Frontend::ProfileSelectApplet& frontend_); 118 const Core::Frontend::ProfileSelectApplet& frontend_);
118 ~ProfileSelect() override; 119 ~ProfileSelect() override;
119 120
120 void Initialize() override; 121 void Initialize() override;
121 122
122 bool TransactionComplete() const override;
123 Result GetStatus() const override; 123 Result GetStatus() const override;
124 void ExecuteInteractive() override; 124 void ExecuteInteractive() override;
125 void Execute() override; 125 void Execute() override;
@@ -137,7 +137,6 @@ private:
137 bool complete = false; 137 bool complete = false;
138 Result status = ResultSuccess; 138 Result status = ResultSuccess;
139 std::vector<u8> final_data; 139 std::vector<u8> final_data;
140 Core::System& system;
141}; 140};
142 141
143} // namespace Service::AM::Applets 142} // 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 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/frontend/applets/software_keyboard.h" 6#include "core/frontend/applets/software_keyboard.h"
7#include "core/hle/service/am/am.h" 7#include "core/hle/service/am/am.h"
8#include "core/hle/service/am/applets/applet_software_keyboard.h" 8#include "core/hle/service/am/frontend/applet_software_keyboard.h"
9#include "core/hle/service/am/storage.h"
9 10
10namespace Service::AM::Applets { 11namespace Service::AM::Frontend {
11 12
12namespace { 13namespace {
13 14
@@ -41,14 +42,15 @@ void SetReplyBase(std::vector<u8>& reply, SwkbdState state, SwkbdReplyType reply
41 42
42} // Anonymous namespace 43} // Anonymous namespace
43 44
44SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, 45SoftwareKeyboard::SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_,
46 LibraryAppletMode applet_mode_,
45 Core::Frontend::SoftwareKeyboardApplet& frontend_) 47 Core::Frontend::SoftwareKeyboardApplet& frontend_)
46 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {} 48 : FrontendApplet{system_, applet_, applet_mode_}, frontend{frontend_} {}
47 49
48SoftwareKeyboard::~SoftwareKeyboard() = default; 50SoftwareKeyboard::~SoftwareKeyboard() = default;
49 51
50void SoftwareKeyboard::Initialize() { 52void SoftwareKeyboard::Initialize() {
51 Applet::Initialize(); 53 FrontendApplet::Initialize();
52 54
53 LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}", 55 LOG_INFO(Service_AM, "Initializing Software Keyboard Applet with LibraryAppletMode={}",
54 applet_mode); 56 applet_mode);
@@ -76,10 +78,6 @@ void SoftwareKeyboard::Initialize() {
76 } 78 }
77} 79}
78 80
79bool SoftwareKeyboard::TransactionComplete() const {
80 return complete;
81}
82
83Result SoftwareKeyboard::GetStatus() const { 81Result SoftwareKeyboard::GetStatus() const {
84 return status; 82 return status;
85} 83}
@@ -184,7 +182,7 @@ void SoftwareKeyboard::InitializeForeground() {
184 182
185 is_background = false; 183 is_background = false;
186 184
187 const auto swkbd_config_storage = broker.PopNormalDataToApplet(); 185 const auto swkbd_config_storage = PopInData();
188 ASSERT(swkbd_config_storage != nullptr); 186 ASSERT(swkbd_config_storage != nullptr);
189 187
190 const auto& swkbd_config_data = swkbd_config_storage->GetData(); 188 const auto& swkbd_config_data = swkbd_config_storage->GetData();
@@ -221,7 +219,7 @@ void SoftwareKeyboard::InitializeForeground() {
221 break; 219 break;
222 } 220 }
223 221
224 const auto work_buffer_storage = broker.PopNormalDataToApplet(); 222 const auto work_buffer_storage = PopInData();
225 ASSERT(work_buffer_storage != nullptr); 223 ASSERT(work_buffer_storage != nullptr);
226 224
227 if (swkbd_config_common.initial_string_length == 0) { 225 if (swkbd_config_common.initial_string_length == 0) {
@@ -250,7 +248,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
250 248
251 is_background = true; 249 is_background = true;
252 250
253 const auto swkbd_inline_initialize_arg_storage = broker.PopNormalDataToApplet(); 251 const auto swkbd_inline_initialize_arg_storage = PopInData();
254 ASSERT(swkbd_inline_initialize_arg_storage != nullptr); 252 ASSERT(swkbd_inline_initialize_arg_storage != nullptr);
255 253
256 const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData(); 254 const auto& swkbd_inline_initialize_arg = swkbd_inline_initialize_arg_storage->GetData();
@@ -267,7 +265,7 @@ void SoftwareKeyboard::InitializeBackground(LibraryAppletMode library_applet_mod
267} 265}
268 266
269void SoftwareKeyboard::ProcessTextCheck() { 267void SoftwareKeyboard::ProcessTextCheck() {
270 const auto text_check_storage = broker.PopInteractiveDataToApplet(); 268 const auto text_check_storage = PopInteractiveInData();
271 ASSERT(text_check_storage != nullptr); 269 ASSERT(text_check_storage != nullptr);
272 270
273 const auto& text_check_data = text_check_storage->GetData(); 271 const auto& text_check_data = text_check_storage->GetData();
@@ -314,7 +312,7 @@ void SoftwareKeyboard::ProcessTextCheck() {
314} 312}
315 313
316void SoftwareKeyboard::ProcessInlineKeyboardRequest() { 314void SoftwareKeyboard::ProcessInlineKeyboardRequest() {
317 const auto request_data_storage = broker.PopInteractiveDataToApplet(); 315 const auto request_data_storage = PopInteractiveInData();
318 ASSERT(request_data_storage != nullptr); 316 ASSERT(request_data_storage != nullptr);
319 317
320 const auto& request_data = request_data_storage->GetData(); 318 const auto& request_data = request_data_storage->GetData();
@@ -377,7 +375,7 @@ void SoftwareKeyboard::SubmitNormalOutputAndExit(SwkbdResult result,
377 submitted_text.size() * sizeof(char16_t)); 375 submitted_text.size() * sizeof(char16_t));
378 } 376 }
379 377
380 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 378 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
381 379
382 ExitKeyboard(); 380 ExitKeyboard();
383} 381}
@@ -410,7 +408,7 @@ void SoftwareKeyboard::SubmitForTextCheck(std::u16string submitted_text) {
410 current_text.size() * sizeof(char16_t)); 408 current_text.size() * sizeof(char16_t));
411 } 409 }
412 410
413 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 411 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(out_data)));
414} 412}
415 413
416void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) { 414void SoftwareKeyboard::SendReply(SwkbdReplyType reply_type) {
@@ -767,7 +765,7 @@ void SoftwareKeyboard::ExitKeyboard() {
767 765
768 frontend.ExitKeyboard(); 766 frontend.ExitKeyboard();
769 767
770 broker.SignalStateChanged(); 768 Exit();
771} 769}
772 770
773Result SoftwareKeyboard::RequestExit() { 771Result SoftwareKeyboard::RequestExit() {
@@ -967,7 +965,7 @@ void SoftwareKeyboard::ReplyFinishedInitialize() {
967 965
968 SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize); 966 SetReplyBase(reply, swkbd_state, SwkbdReplyType::FinishedInitialize);
969 967
970 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 968 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
971} 969}
972 970
973void SoftwareKeyboard::ReplyDefault() { 971void SoftwareKeyboard::ReplyDefault() {
@@ -977,7 +975,7 @@ void SoftwareKeyboard::ReplyDefault() {
977 975
978 SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default); 976 SetReplyBase(reply, swkbd_state, SwkbdReplyType::Default);
979 977
980 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 978 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
981} 979}
982 980
983void SoftwareKeyboard::ReplyChangedString() { 981void SoftwareKeyboard::ReplyChangedString() {
@@ -999,7 +997,7 @@ void SoftwareKeyboard::ReplyChangedString() {
999 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg, 997 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &changed_string_arg,
1000 sizeof(SwkbdChangedStringArg)); 998 sizeof(SwkbdChangedStringArg));
1001 999
1002 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1000 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1003} 1001}
1004 1002
1005void SoftwareKeyboard::ReplyMovedCursor() { 1003void SoftwareKeyboard::ReplyMovedCursor() {
@@ -1019,7 +1017,7 @@ void SoftwareKeyboard::ReplyMovedCursor() {
1019 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg, 1017 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_cursor_arg,
1020 sizeof(SwkbdMovedCursorArg)); 1018 sizeof(SwkbdMovedCursorArg));
1021 1019
1022 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1020 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1023} 1021}
1024 1022
1025void SoftwareKeyboard::ReplyMovedTab() { 1023void SoftwareKeyboard::ReplyMovedTab() {
@@ -1039,7 +1037,7 @@ void SoftwareKeyboard::ReplyMovedTab() {
1039 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg, 1037 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &moved_tab_arg,
1040 sizeof(SwkbdMovedTabArg)); 1038 sizeof(SwkbdMovedTabArg));
1041 1039
1042 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1040 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1043} 1041}
1044 1042
1045void SoftwareKeyboard::ReplyDecidedEnter() { 1043void SoftwareKeyboard::ReplyDecidedEnter() {
@@ -1058,7 +1056,7 @@ void SoftwareKeyboard::ReplyDecidedEnter() {
1058 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg, 1056 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE, &decided_enter_arg,
1059 sizeof(SwkbdDecidedEnterArg)); 1057 sizeof(SwkbdDecidedEnterArg));
1060 1058
1061 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1059 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1062 1060
1063 HideInlineKeyboard(); 1061 HideInlineKeyboard();
1064} 1062}
@@ -1070,7 +1068,7 @@ void SoftwareKeyboard::ReplyDecidedCancel() {
1070 1068
1071 SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel); 1069 SetReplyBase(reply, swkbd_state, SwkbdReplyType::DecidedCancel);
1072 1070
1073 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1071 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1074 1072
1075 HideInlineKeyboard(); 1073 HideInlineKeyboard();
1076} 1074}
@@ -1095,7 +1093,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8() {
1095 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg, 1093 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &changed_string_arg,
1096 sizeof(SwkbdChangedStringArg)); 1094 sizeof(SwkbdChangedStringArg));
1097 1095
1098 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1096 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1099} 1097}
1100 1098
1101void SoftwareKeyboard::ReplyMovedCursorUtf8() { 1099void SoftwareKeyboard::ReplyMovedCursorUtf8() {
@@ -1116,7 +1114,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8() {
1116 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg, 1114 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &moved_cursor_arg,
1117 sizeof(SwkbdMovedCursorArg)); 1115 sizeof(SwkbdMovedCursorArg));
1118 1116
1119 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1117 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1120} 1118}
1121 1119
1122void SoftwareKeyboard::ReplyDecidedEnterUtf8() { 1120void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
@@ -1136,7 +1134,7 @@ void SoftwareKeyboard::ReplyDecidedEnterUtf8() {
1136 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg, 1134 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE, &decided_enter_arg,
1137 sizeof(SwkbdDecidedEnterArg)); 1135 sizeof(SwkbdDecidedEnterArg));
1138 1136
1139 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1137 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1140 1138
1141 HideInlineKeyboard(); 1139 HideInlineKeyboard();
1142} 1140}
@@ -1148,7 +1146,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizeDic() {
1148 1146
1149 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic); 1147 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizeDic);
1150 1148
1151 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1149 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1152} 1150}
1153 1151
1154void SoftwareKeyboard::ReplyReleasedUserWordInfo() { 1152void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
@@ -1158,7 +1156,7 @@ void SoftwareKeyboard::ReplyReleasedUserWordInfo() {
1158 1156
1159 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo); 1157 SetReplyBase(reply, swkbd_state, SwkbdReplyType::ReleasedUserWordInfo);
1160 1158
1161 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1159 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1162} 1160}
1163 1161
1164void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() { 1162void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
@@ -1168,7 +1166,7 @@ void SoftwareKeyboard::ReplyUnsetCustomizedDictionaries() {
1168 1166
1169 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries); 1167 SetReplyBase(reply, swkbd_state, SwkbdReplyType::UnsetCustomizedDictionaries);
1170 1168
1171 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1169 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1172} 1170}
1173 1171
1174void SoftwareKeyboard::ReplyChangedStringV2() { 1172void SoftwareKeyboard::ReplyChangedStringV2() {
@@ -1194,7 +1192,7 @@ void SoftwareKeyboard::ReplyChangedStringV2() {
1194 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg), 1192 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdChangedStringArg),
1195 &flag, 1); 1193 &flag, 1);
1196 1194
1197 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1195 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1198} 1196}
1199 1197
1200void SoftwareKeyboard::ReplyMovedCursorV2() { 1198void SoftwareKeyboard::ReplyMovedCursorV2() {
@@ -1218,7 +1216,7 @@ void SoftwareKeyboard::ReplyMovedCursorV2() {
1218 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg), 1216 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF16_SIZE + sizeof(SwkbdMovedCursorArg),
1219 &flag, 1); 1217 &flag, 1);
1220 1218
1221 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1219 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1222} 1220}
1223 1221
1224void SoftwareKeyboard::ReplyChangedStringUtf8V2() { 1222void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
@@ -1245,7 +1243,7 @@ void SoftwareKeyboard::ReplyChangedStringUtf8V2() {
1245 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg), 1243 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdChangedStringArg),
1246 &flag, 1); 1244 &flag, 1);
1247 1245
1248 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1246 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1249} 1247}
1250 1248
1251void SoftwareKeyboard::ReplyMovedCursorUtf8V2() { 1249void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
@@ -1270,7 +1268,7 @@ void SoftwareKeyboard::ReplyMovedCursorUtf8V2() {
1270 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg), 1268 std::memcpy(reply.data() + REPLY_BASE_SIZE + REPLY_UTF8_SIZE + sizeof(SwkbdMovedCursorArg),
1271 &flag, 1); 1269 &flag, 1);
1272 1270
1273 broker.PushInteractiveDataFromApplet(std::make_shared<IStorage>(system, std::move(reply))); 1271 PushInteractiveOutData(std::make_shared<IStorage>(system, std::move(reply)));
1274} 1272}
1275 1273
1276} // namespace Service::AM::Applets 1274} // 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 @@
5 5
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/hle/result.h" 7#include "core/hle/result.h"
8#include "core/hle/service/am/applets/applet_software_keyboard_types.h" 8#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
9#include "core/hle/service/am/applets/applets.h" 9#include "core/hle/service/am/frontend/applets.h"
10 10
11namespace Core { 11namespace Core {
12class System; 12class System;
@@ -17,17 +17,17 @@ struct KeyboardInitializeParameters;
17struct InlineAppearParameters; 17struct InlineAppearParameters;
18} // namespace Core::Frontend 18} // namespace Core::Frontend
19 19
20namespace Service::AM::Applets { 20namespace Service::AM::Frontend {
21 21
22class SoftwareKeyboard final : public Applet { 22class SoftwareKeyboard final : public FrontendApplet {
23public: 23public:
24 explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_, 24 explicit SoftwareKeyboard(Core::System& system_, std::shared_ptr<Applet> applet_,
25 LibraryAppletMode applet_mode_,
25 Core::Frontend::SoftwareKeyboardApplet& frontend_); 26 Core::Frontend::SoftwareKeyboardApplet& frontend_);
26 ~SoftwareKeyboard() override; 27 ~SoftwareKeyboard() override;
27 28
28 void Initialize() override; 29 void Initialize() override;
29 30
30 bool TransactionComplete() const override;
31 Result GetStatus() const override; 31 Result GetStatus() const override;
32 void ExecuteInteractive() override; 32 void ExecuteInteractive() override;
33 void Execute() override; 33 void Execute() override;
@@ -156,7 +156,6 @@ private:
156 void ReplyMovedCursorUtf8V2(); 156 void ReplyMovedCursorUtf8V2();
157 157
158 Core::Frontend::SoftwareKeyboardApplet& frontend; 158 Core::Frontend::SoftwareKeyboardApplet& frontend;
159 Core::System& system;
160 159
161 SwkbdAppletVersion swkbd_applet_version; 160 SwkbdAppletVersion swkbd_applet_version;
162 161
@@ -184,4 +183,4 @@ private:
184 Result status{ResultSuccess}; 183 Result status{ResultSuccess};
185}; 184};
186 185
187} // namespace Service::AM::Applets 186} // 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 @@
11#include "common/swap.h" 11#include "common/swap.h"
12#include "common/uuid.h" 12#include "common/uuid.h"
13 13
14namespace Service::AM::Applets { 14namespace Service::AM::Frontend {
15 15
16constexpr std::size_t MAX_OK_TEXT_LENGTH = 8; 16constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
17constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64; 17constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
@@ -351,4 +351,4 @@ struct SwkbdDecidedEnterArg {
351}; 351};
352static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size."); 352static_assert(sizeof(SwkbdDecidedEnterArg) == 0x4, "SwkbdDecidedEnterArg has incorrect size.");
353 353
354} // namespace Service::AM::Applets 354} // 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 @@
19#include "core/frontend/applets/web_browser.h" 19#include "core/frontend/applets/web_browser.h"
20#include "core/hle/result.h" 20#include "core/hle/result.h"
21#include "core/hle/service/am/am.h" 21#include "core/hle/service/am/am.h"
22#include "core/hle/service/am/applets/applet_web_browser.h" 22#include "core/hle/service/am/frontend/applet_web_browser.h"
23#include "core/hle/service/am/storage.h"
23#include "core/hle/service/filesystem/filesystem.h" 24#include "core/hle/service/filesystem/filesystem.h"
24#include "core/hle/service/ns/iplatform_service_manager.h" 25#include "core/hle/service/ns/iplatform_service_manager.h"
25#include "core/loader/loader.h" 26#include "core/loader/loader.h"
26 27
27namespace Service::AM::Applets { 28namespace Service::AM::Frontend {
28 29
29namespace { 30namespace {
30 31
@@ -223,14 +224,15 @@ void ExtractSharedFonts(Core::System& system) {
223 224
224} // namespace 225} // namespace
225 226
226WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, 227WebBrowser::WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
228 LibraryAppletMode applet_mode_,
227 const Core::Frontend::WebBrowserApplet& frontend_) 229 const Core::Frontend::WebBrowserApplet& frontend_)
228 : Applet{system_, applet_mode_}, frontend(frontend_), system{system_} {} 230 : FrontendApplet{system_, applet_, applet_mode_}, frontend(frontend_) {}
229 231
230WebBrowser::~WebBrowser() = default; 232WebBrowser::~WebBrowser() = default;
231 233
232void WebBrowser::Initialize() { 234void WebBrowser::Initialize() {
233 Applet::Initialize(); 235 FrontendApplet::Initialize();
234 236
235 LOG_INFO(Service_AM, "Initializing Web Browser Applet."); 237 LOG_INFO(Service_AM, "Initializing Web Browser Applet.");
236 238
@@ -243,7 +245,7 @@ void WebBrowser::Initialize() {
243 245
244 web_applet_version = WebAppletVersion{common_args.library_version}; 246 web_applet_version = WebAppletVersion{common_args.library_version};
245 247
246 const auto web_arg_storage = broker.PopNormalDataToApplet(); 248 const auto web_arg_storage = PopInData();
247 ASSERT(web_arg_storage != nullptr); 249 ASSERT(web_arg_storage != nullptr);
248 250
249 const auto& web_arg = web_arg_storage->GetData(); 251 const auto& web_arg = web_arg_storage->GetData();
@@ -284,10 +286,6 @@ void WebBrowser::Initialize() {
284 } 286 }
285} 287}
286 288
287bool WebBrowser::TransactionComplete() const {
288 return complete;
289}
290
291Result WebBrowser::GetStatus() const { 289Result WebBrowser::GetStatus() const {
292 return status; 290 return status;
293} 291}
@@ -358,8 +356,8 @@ void WebBrowser::WebBrowserExit(WebExitReason exit_reason, std::string last_url)
358 complete = true; 356 complete = true;
359 std::vector<u8> out_data(sizeof(WebCommonReturnValue)); 357 std::vector<u8> out_data(sizeof(WebCommonReturnValue));
360 std::memcpy(out_data.data(), &web_common_return_value, out_data.size()); 358 std::memcpy(out_data.data(), &web_common_return_value, out_data.size());
361 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); 359 PushOutData(std::make_shared<IStorage>(system, std::move(out_data)));
362 broker.SignalStateChanged(); 360 Exit();
363} 361}
364 362
365Result WebBrowser::RequestExit() { 363Result WebBrowser::RequestExit() {
@@ -504,4 +502,4 @@ void WebBrowser::ExecuteLobby() {
504 LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented"); 502 LOG_WARNING(Service_AM, "(STUBBED) called, Lobby Applet is not implemented");
505 WebBrowserExit(WebExitReason::EndButtonPressed); 503 WebBrowserExit(WebExitReason::EndButtonPressed);
506} 504}
507} // namespace Service::AM::Applets 505} // 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 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/file_sys/vfs/vfs_types.h" 10#include "core/file_sys/vfs/vfs_types.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12#include "core/hle/service/am/applets/applet_web_browser_types.h" 12#include "core/hle/service/am/frontend/applet_web_browser_types.h"
13#include "core/hle/service/am/applets/applets.h" 13#include "core/hle/service/am/frontend/applets.h"
14 14
15namespace Core { 15namespace Core {
16class System; 16class System;
@@ -20,18 +20,17 @@ namespace FileSys {
20enum class ContentRecordType : u8; 20enum class ContentRecordType : u8;
21} 21}
22 22
23namespace Service::AM::Applets { 23namespace Service::AM::Frontend {
24 24
25class WebBrowser final : public Applet { 25class WebBrowser final : public FrontendApplet {
26public: 26public:
27 WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_, 27 WebBrowser(Core::System& system_, std::shared_ptr<Applet> applet_,
28 const Core::Frontend::WebBrowserApplet& frontend_); 28 LibraryAppletMode applet_mode_, const Core::Frontend::WebBrowserApplet& frontend_);
29 29
30 ~WebBrowser() override; 30 ~WebBrowser() override;
31 31
32 void Initialize() override; 32 void Initialize() override;
33 33
34 bool TransactionComplete() const override;
35 Result GetStatus() const override; 34 Result GetStatus() const override;
36 void ExecuteInteractive() override; 35 void ExecuteInteractive() override;
37 void Execute() override; 36 void Execute() override;
@@ -80,8 +79,6 @@ private:
80 FileSys::VirtualFile offline_romfs; 79 FileSys::VirtualFile offline_romfs;
81 80
82 std::string external_url; 81 std::string external_url;
83
84 Core::System& system;
85}; 82};
86 83
87} // namespace Service::AM::Applets 84} // 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 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/swap.h" 12#include "common/swap.h"
13 13
14namespace Service::AM::Applets { 14namespace Service::AM::Frontend {
15 15
16enum class WebAppletVersion : u32_le { 16enum class WebAppletVersion : u32_le {
17 Version0 = 0x0, // Only used by WifiWebAuthApplet 17 Version0 = 0x0, // Only used by WifiWebAuthApplet
@@ -174,4 +174,4 @@ static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has
174 174
175using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>; 175using WebArgInputTLVMap = std::unordered_map<WebArgInputTLVType, std::vector<u8>>;
176 176
177} // namespace Service::AM::Applets 177} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cstring>
5
6#include "common/assert.h"
7#include "core/core.h"
8#include "core/frontend/applets/cabinet.h"
9#include "core/frontend/applets/controller.h"
10#include "core/frontend/applets/error.h"
11#include "core/frontend/applets/general.h"
12#include "core/frontend/applets/mii_edit.h"
13#include "core/frontend/applets/profile_select.h"
14#include "core/frontend/applets/software_keyboard.h"
15#include "core/frontend/applets/web_browser.h"
16#include "core/hle/kernel/k_event.h"
17#include "core/hle/service/am/am.h"
18#include "core/hle/service/am/applet_ae.h"
19#include "core/hle/service/am/applet_data_broker.h"
20#include "core/hle/service/am/applet_manager.h"
21#include "core/hle/service/am/applet_message_queue.h"
22#include "core/hle/service/am/applet_oe.h"
23#include "core/hle/service/am/frontend/applet_cabinet.h"
24#include "core/hle/service/am/frontend/applet_controller.h"
25#include "core/hle/service/am/frontend/applet_error.h"
26#include "core/hle/service/am/frontend/applet_general.h"
27#include "core/hle/service/am/frontend/applet_mii_edit.h"
28#include "core/hle/service/am/frontend/applet_profile_select.h"
29#include "core/hle/service/am/frontend/applet_software_keyboard.h"
30#include "core/hle/service/am/frontend/applet_web_browser.h"
31#include "core/hle/service/am/frontend/applets.h"
32#include "core/hle/service/am/storage.h"
33#include "core/hle/service/sm/sm.h"
34
35namespace Service::AM::Frontend {
36
37FrontendApplet::FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_,
38 LibraryAppletMode applet_mode_)
39 : system{system_}, applet{std::move(applet_)}, applet_mode{applet_mode_} {}
40
41FrontendApplet::~FrontendApplet() = default;
42
43void FrontendApplet::Initialize() {
44 std::shared_ptr<IStorage> common = PopInData();
45 ASSERT(common != nullptr);
46 const auto common_data = common->GetData();
47
48 ASSERT(common_data.size() >= sizeof(CommonArguments));
49 std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
50
51 initialized = true;
52}
53
54std::shared_ptr<IStorage> FrontendApplet::PopInData() {
55 std::shared_ptr<IStorage> ret;
56 applet.lock()->caller_applet_broker->GetInData().Pop(&ret);
57 return ret;
58}
59
60std::shared_ptr<IStorage> FrontendApplet::PopInteractiveInData() {
61 std::shared_ptr<IStorage> ret;
62 applet.lock()->caller_applet_broker->GetInteractiveInData().Pop(&ret);
63 return ret;
64}
65
66void FrontendApplet::PushOutData(std::shared_ptr<IStorage> storage) {
67 applet.lock()->caller_applet_broker->GetOutData().Push(storage);
68}
69
70void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
71 applet.lock()->caller_applet_broker->GetInteractiveOutData().Push(storage);
72}
73
74void FrontendApplet::Exit() {
75 applet.lock()->caller_applet_broker->SignalCompletion();
76}
77
78FrontendAppletSet::FrontendAppletSet() = default;
79
80FrontendAppletSet::FrontendAppletSet(CabinetApplet cabinet_applet,
81 ControllerApplet controller_applet, ErrorApplet error_applet,
82 MiiEdit mii_edit_,
83 ParentalControlsApplet parental_controls_applet,
84 PhotoViewer photo_viewer_, ProfileSelect profile_select_,
85 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
86 : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
87 error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
88 parental_controls{std::move(parental_controls_applet)},
89 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
90 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
91
92FrontendAppletSet::~FrontendAppletSet() = default;
93
94FrontendAppletSet::FrontendAppletSet(FrontendAppletSet&&) noexcept = default;
95
96FrontendAppletSet& FrontendAppletSet::operator=(FrontendAppletSet&&) noexcept = default;
97
98FrontendAppletHolder::FrontendAppletHolder(Core::System& system_) : system{system_} {}
99
100FrontendAppletHolder::~FrontendAppletHolder() = default;
101
102const FrontendAppletSet& FrontendAppletHolder::GetFrontendAppletSet() const {
103 return frontend;
104}
105
106NFP::CabinetMode FrontendAppletHolder::GetCabinetMode() const {
107 return cabinet_mode;
108}
109
110AppletId FrontendAppletHolder::GetCurrentAppletId() const {
111 return current_applet_id;
112}
113
114void FrontendAppletHolder::SetFrontendAppletSet(FrontendAppletSet set) {
115 if (set.cabinet != nullptr) {
116 frontend.cabinet = std::move(set.cabinet);
117 }
118
119 if (set.controller != nullptr) {
120 frontend.controller = std::move(set.controller);
121 }
122
123 if (set.error != nullptr) {
124 frontend.error = std::move(set.error);
125 }
126
127 if (set.mii_edit != nullptr) {
128 frontend.mii_edit = std::move(set.mii_edit);
129 }
130
131 if (set.parental_controls != nullptr) {
132 frontend.parental_controls = std::move(set.parental_controls);
133 }
134
135 if (set.photo_viewer != nullptr) {
136 frontend.photo_viewer = std::move(set.photo_viewer);
137 }
138
139 if (set.profile_select != nullptr) {
140 frontend.profile_select = std::move(set.profile_select);
141 }
142
143 if (set.software_keyboard != nullptr) {
144 frontend.software_keyboard = std::move(set.software_keyboard);
145 }
146
147 if (set.web_browser != nullptr) {
148 frontend.web_browser = std::move(set.web_browser);
149 }
150}
151
152void FrontendAppletHolder::SetCabinetMode(NFP::CabinetMode mode) {
153 cabinet_mode = mode;
154}
155
156void FrontendAppletHolder::SetCurrentAppletId(AppletId applet_id) {
157 current_applet_id = applet_id;
158}
159
160void FrontendAppletHolder::SetDefaultAppletsIfMissing() {
161 if (frontend.cabinet == nullptr) {
162 frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
163 }
164
165 if (frontend.controller == nullptr) {
166 frontend.controller =
167 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
168 }
169
170 if (frontend.error == nullptr) {
171 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
172 }
173
174 if (frontend.mii_edit == nullptr) {
175 frontend.mii_edit = std::make_unique<Core::Frontend::DefaultMiiEditApplet>();
176 }
177
178 if (frontend.parental_controls == nullptr) {
179 frontend.parental_controls =
180 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
181 }
182
183 if (frontend.photo_viewer == nullptr) {
184 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
185 }
186
187 if (frontend.profile_select == nullptr) {
188 frontend.profile_select = std::make_unique<Core::Frontend::DefaultProfileSelectApplet>();
189 }
190
191 if (frontend.software_keyboard == nullptr) {
192 frontend.software_keyboard =
193 std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
194 }
195
196 if (frontend.web_browser == nullptr) {
197 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
198 }
199}
200
201void FrontendAppletHolder::ClearAll() {
202 frontend = {};
203}
204
205std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<Applet> applet,
206 AppletId id,
207 LibraryAppletMode mode) const {
208 switch (id) {
209 case AppletId::Auth:
210 return std::make_shared<Auth>(system, applet, mode, *frontend.parental_controls);
211 case AppletId::Cabinet:
212 return std::make_shared<Cabinet>(system, applet, mode, *frontend.cabinet);
213 case AppletId::Controller:
214 return std::make_shared<Controller>(system, applet, mode, *frontend.controller);
215 case AppletId::Error:
216 return std::make_shared<Error>(system, applet, mode, *frontend.error);
217 case AppletId::ProfileSelect:
218 return std::make_shared<ProfileSelect>(system, applet, mode, *frontend.profile_select);
219 case AppletId::SoftwareKeyboard:
220 return std::make_shared<SoftwareKeyboard>(system, applet, mode,
221 *frontend.software_keyboard);
222 case AppletId::MiiEdit:
223 return std::make_shared<MiiEdit>(system, applet, mode, *frontend.mii_edit);
224 case AppletId::Web:
225 case AppletId::Shop:
226 case AppletId::OfflineWeb:
227 case AppletId::LoginShare:
228 case AppletId::WebAuth:
229 return std::make_shared<WebBrowser>(system, applet, mode, *frontend.web_browser);
230 case AppletId::PhotoViewer:
231 return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
232 default:
233 UNIMPLEMENTED_MSG(
234 "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
235 static_cast<u8>(id));
236 return std::make_shared<StubApplet>(system, applet, id, mode);
237 }
238}
239
240} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7#include <queue>
8
9#include "common/swap.h"
10#include "core/hle/service/am/applet.h"
11
12union Result;
13
14namespace Core {
15class System;
16}
17
18namespace Core::Frontend {
19class CabinetApplet;
20class ControllerApplet;
21class ECommerceApplet;
22class ErrorApplet;
23class MiiEditApplet;
24class ParentalControlsApplet;
25class PhotoViewerApplet;
26class ProfileSelectApplet;
27class SoftwareKeyboardApplet;
28class WebBrowserApplet;
29} // namespace Core::Frontend
30
31namespace Kernel {
32class KernelCore;
33class KEvent;
34class KReadableEvent;
35} // namespace Kernel
36
37namespace Service::NFP {
38enum class CabinetMode : u8;
39} // namespace Service::NFP
40
41namespace Service::AM {
42
43class IStorage;
44
45namespace Frontend {
46
47class FrontendApplet {
48public:
49 explicit FrontendApplet(Core::System& system_, std::shared_ptr<Applet> applet_,
50 LibraryAppletMode applet_mode_);
51 virtual ~FrontendApplet();
52
53 virtual void Initialize();
54
55 virtual Result GetStatus() const = 0;
56 virtual void ExecuteInteractive() = 0;
57 virtual void Execute() = 0;
58 virtual Result RequestExit() = 0;
59
60 LibraryAppletMode GetLibraryAppletMode() const {
61 return applet_mode;
62 }
63
64 bool IsInitialized() const {
65 return initialized;
66 }
67
68protected:
69 std::shared_ptr<IStorage> PopInData();
70 std::shared_ptr<IStorage> PopInteractiveInData();
71 void PushOutData(std::shared_ptr<IStorage> storage);
72 void PushInteractiveOutData(std::shared_ptr<IStorage> storage);
73 void Exit();
74
75protected:
76 Core::System& system;
77 CommonArguments common_args{};
78 std::weak_ptr<Applet> applet{};
79 LibraryAppletMode applet_mode{};
80 bool initialized{false};
81};
82
83struct FrontendAppletSet {
84 using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
85 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
86 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
87 using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
88 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
89 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
90 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
91 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
92 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
93
94 FrontendAppletSet();
95 FrontendAppletSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
96 ErrorApplet error_applet, MiiEdit mii_edit_,
97 ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
98 ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
99 WebBrowser web_browser_);
100 ~FrontendAppletSet();
101
102 FrontendAppletSet(const FrontendAppletSet&) = delete;
103 FrontendAppletSet& operator=(const FrontendAppletSet&) = delete;
104
105 FrontendAppletSet(FrontendAppletSet&&) noexcept;
106 FrontendAppletSet& operator=(FrontendAppletSet&&) noexcept;
107
108 CabinetApplet cabinet;
109 ControllerApplet controller;
110 ErrorApplet error;
111 MiiEdit mii_edit;
112 ParentalControlsApplet parental_controls;
113 PhotoViewer photo_viewer;
114 ProfileSelect profile_select;
115 SoftwareKeyboard software_keyboard;
116 WebBrowser web_browser;
117};
118
119class FrontendAppletHolder {
120public:
121 explicit FrontendAppletHolder(Core::System& system_);
122 ~FrontendAppletHolder();
123
124 const FrontendAppletSet& GetFrontendAppletSet() const;
125 NFP::CabinetMode GetCabinetMode() const;
126 AppletId GetCurrentAppletId() const;
127
128 void SetFrontendAppletSet(FrontendAppletSet set);
129 void SetCabinetMode(NFP::CabinetMode mode);
130 void SetCurrentAppletId(AppletId applet_id);
131 void SetDefaultAppletsIfMissing();
132 void ClearAll();
133
134 std::shared_ptr<FrontendApplet> GetApplet(std::shared_ptr<Applet> applet, AppletId id,
135 LibraryAppletMode mode) const;
136
137private:
138 AppletId current_applet_id{};
139 NFP::CabinetMode cabinet_mode{};
140
141 FrontendAppletSet frontend;
142 Core::System& system;
143};
144
145} // namespace Frontend
146} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/global_state_controller.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IGlobalStateController::IGlobalStateController(Core::System& system_)
10 : ServiceFramework{system_, "IGlobalStateController"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "RequestToEnterSleep"},
14 {1, nullptr, "EnterSleep"},
15 {2, nullptr, "StartSleepSequence"},
16 {3, nullptr, "StartShutdownSequence"},
17 {4, nullptr, "StartRebootSequence"},
18 {9, nullptr, "IsAutoPowerDownRequested"},
19 {10, nullptr, "LoadAndApplyIdlePolicySettings"},
20 {11, nullptr, "NotifyCecSettingsChanged"},
21 {12, nullptr, "SetDefaultHomeButtonLongPressTime"},
22 {13, nullptr, "UpdateDefaultDisplayResolution"},
23 {14, nullptr, "ShouldSleepOnBoot"},
24 {15, nullptr, "GetHdcpAuthenticationFailedEvent"},
25 {30, nullptr, "OpenCradleFirmwareUpdater"},
26 };
27 // clang-format on
28
29 RegisterHandlers(functions);
30}
31
32IGlobalStateController::~IGlobalStateController() = default;
33
34} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
11public:
12 explicit IGlobalStateController(Core::System& system_);
13 ~IGlobalStateController() override;
14};
15
16} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/core.h"
5#include "core/hle/service/am/hid_registration.h"
6#include "core/hle/service/am/process.h"
7#include "core/hle/service/hid/hid_server.h"
8#include "core/hle/service/sm/sm.h"
9#include "hid_core/resource_manager.h"
10
11namespace Service::AM {
12
13HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) {
14 m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid");
15
16 if (m_process.IsInitialized()) {
17 m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
18 true);
19 }
20}
21
22HidRegistration::~HidRegistration() {
23 if (m_process.IsInitialized()) {
24 m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId(
25 m_process.GetProcessId());
26 }
27}
28
29void HidRegistration::EnableAppletToGetInput(bool enable) {
30 if (m_process.IsInitialized()) {
31 m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
32 }
33}
34
35} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7
8namespace Core {
9class System;
10}
11
12namespace Service::HID {
13class IHidServer;
14}
15
16namespace Service::AM {
17
18class Process;
19
20class HidRegistration {
21public:
22 explicit HidRegistration(Core::System& system, Process& process);
23 ~HidRegistration();
24
25 void EnableAppletToGetInput(bool enable);
26
27private:
28 Process& m_process;
29 std::shared_ptr<Service::HID::IHidServer> m_hid_server;
30};
31
32} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/home_menu_functions.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_)
10 : ServiceFramework{system_, "IHomeMenuFunctions"}, service_context{system,
11 "IHomeMenuFunctions"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
15 {11, nullptr, "LockForeground"},
16 {12, nullptr, "UnlockForeground"},
17 {20, nullptr, "PopFromGeneralChannel"},
18 {21, &IHomeMenuFunctions::GetPopFromGeneralChannelEvent, "GetPopFromGeneralChannelEvent"},
19 {30, nullptr, "GetHomeButtonWriterLockAccessor"},
20 {31, nullptr, "GetWriterLockAccessorEx"},
21 {40, nullptr, "IsSleepEnabled"},
22 {41, nullptr, "IsRebootEnabled"},
23 {50, nullptr, "LaunchSystemApplet"},
24 {51, nullptr, "LaunchStarter"},
25 {100, nullptr, "PopRequestLaunchApplicationForDebug"},
26 {110, nullptr, "IsForceTerminateApplicationDisabledForDebug"},
27 {200, nullptr, "LaunchDevMenu"},
28 {1000, nullptr, "SetLastApplicationExitReason"},
29 };
30 // clang-format on
31
32 RegisterHandlers(functions);
33
34 pop_from_general_channel_event =
35 service_context.CreateEvent("IHomeMenuFunctions:PopFromGeneralChannelEvent");
36}
37
38IHomeMenuFunctions::~IHomeMenuFunctions() {
39 service_context.CloseEvent(pop_from_general_channel_event);
40}
41
42void IHomeMenuFunctions::RequestToGetForeground(HLERequestContext& ctx) {
43 LOG_WARNING(Service_AM, "(STUBBED) called");
44
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(ResultSuccess);
47}
48
49void IHomeMenuFunctions::GetPopFromGeneralChannelEvent(HLERequestContext& ctx) {
50 LOG_WARNING(Service_AM, "(STUBBED) called");
51
52 IPC::ResponseBuilder rb{ctx, 2, 1};
53 rb.Push(ResultSuccess);
54 rb.PushCopyObjects(pop_from_general_channel_event->GetReadableEvent());
55}
56
57} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
12public:
13 explicit IHomeMenuFunctions(Core::System& system_);
14 ~IHomeMenuFunctions() override;
15
16private:
17 void RequestToGetForeground(HLERequestContext& ctx);
18 void GetPopFromGeneralChannelEvent(HLERequestContext& ctx);
19
20 KernelHelpers::ServiceContext service_context;
21
22 Kernel::KEvent* pop_from_general_channel_event;
23};
24
25} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/applet_data_broker.h"
7#include "core/hle/service/am/frontend/applets.h"
8#include "core/hle/service/am/library_applet_accessor.h"
9#include "core/hle/service/am/storage.h"
10#include "core/hle/service/ipc_helpers.h"
11
12namespace Service::AM {
13
14ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
15 std::shared_ptr<AppletDataBroker> broker_,
16 std::shared_ptr<Applet> applet_)
17 : ServiceFramework{system_, "ILibraryAppletAccessor"}, broker{std::move(broker_)},
18 applet{std::move(applet_)} {
19 // clang-format off
20 static const FunctionInfo functions[] = {
21 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
22 {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
23 {10, &ILibraryAppletAccessor::Start, "Start"},
24 {20, &ILibraryAppletAccessor::RequestExit, "RequestExit"},
25 {25, nullptr, "Terminate"},
26 {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
27 {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
28 {60, &ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero, "PresetLibraryAppletGpuTimeSliceZero"},
29 {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
30 {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
31 {102, nullptr, "PushExtraStorage"},
32 {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
33 {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
34 {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
35 {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
36 {110, nullptr, "NeedsToExitProcess"},
37 {120, nullptr, "GetLibraryAppletInfo"},
38 {150, nullptr, "RequestForAppletToGetForeground"},
39 {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"},
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44}
45
46ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
47
48void ILibraryAppletAccessor::GetAppletStateChangedEvent(HLERequestContext& ctx) {
49 LOG_DEBUG(Service_AM, "called");
50
51 IPC::ResponseBuilder rb{ctx, 2, 1};
52 rb.Push(ResultSuccess);
53 rb.PushCopyObjects(broker->GetStateChangedEvent().GetHandle());
54}
55
56void ILibraryAppletAccessor::IsCompleted(HLERequestContext& ctx) {
57 LOG_DEBUG(Service_AM, "called");
58
59 std::scoped_lock lk{applet->lock};
60
61 IPC::ResponseBuilder rb{ctx, 3};
62 rb.Push(ResultSuccess);
63 rb.Push<u32>(broker->IsCompleted());
64}
65
66void ILibraryAppletAccessor::GetResult(HLERequestContext& ctx) {
67 LOG_DEBUG(Service_AM, "called");
68
69 IPC::ResponseBuilder rb{ctx, 2};
70 rb.Push(applet->terminate_result);
71}
72
73void ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx) {
74 LOG_WARNING(Service_AM, "(STUBBED) called");
75
76 IPC::ResponseBuilder rb{ctx, 2};
77 rb.Push(ResultSuccess);
78}
79
80void ILibraryAppletAccessor::Start(HLERequestContext& ctx) {
81 LOG_DEBUG(Service_AM, "called");
82
83 applet->process->Run();
84 FrontendExecute();
85
86 IPC::ResponseBuilder rb{ctx, 2};
87 rb.Push(ResultSuccess);
88}
89
90void ILibraryAppletAccessor::RequestExit(HLERequestContext& ctx) {
91 LOG_DEBUG(Service_AM, "called");
92
93 ASSERT(applet != nullptr);
94 applet->message_queue.RequestExit();
95 FrontendRequestExit();
96
97 IPC::ResponseBuilder rb{ctx, 2};
98 rb.Push(ResultSuccess);
99}
100
101void ILibraryAppletAccessor::PushInData(HLERequestContext& ctx) {
102 LOG_DEBUG(Service_AM, "called");
103
104 IPC::RequestParser rp{ctx};
105 broker->GetInData().Push(rp.PopIpcInterface<IStorage>().lock());
106
107 IPC::ResponseBuilder rb{ctx, 2};
108 rb.Push(ResultSuccess);
109}
110
111void ILibraryAppletAccessor::PopOutData(HLERequestContext& ctx) {
112 LOG_DEBUG(Service_AM, "called");
113
114 std::shared_ptr<IStorage> data;
115 const auto res = broker->GetOutData().Pop(&data);
116
117 if (res.IsSuccess()) {
118 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
119 rb.Push(res);
120 rb.PushIpcInterface(std::move(data));
121 } else {
122 IPC::ResponseBuilder rb{ctx, 2};
123 rb.Push(res);
124 }
125}
126
127void ILibraryAppletAccessor::PushInteractiveInData(HLERequestContext& ctx) {
128 LOG_DEBUG(Service_AM, "called");
129
130 IPC::RequestParser rp{ctx};
131 broker->GetInteractiveInData().Push(rp.PopIpcInterface<IStorage>().lock());
132 FrontendExecuteInteractive();
133
134 IPC::ResponseBuilder rb{ctx, 2};
135 rb.Push(ResultSuccess);
136}
137
138void ILibraryAppletAccessor::PopInteractiveOutData(HLERequestContext& ctx) {
139 LOG_DEBUG(Service_AM, "called");
140
141 std::shared_ptr<IStorage> data;
142 const auto res = broker->GetInteractiveOutData().Pop(&data);
143
144 if (res.IsSuccess()) {
145 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
146 rb.Push(res);
147 rb.PushIpcInterface(std::move(data));
148 } else {
149 IPC::ResponseBuilder rb{ctx, 2};
150 rb.Push(res);
151 }
152}
153
154void ILibraryAppletAccessor::GetPopOutDataEvent(HLERequestContext& ctx) {
155 LOG_DEBUG(Service_AM, "called");
156
157 IPC::ResponseBuilder rb{ctx, 2, 1};
158 rb.Push(ResultSuccess);
159 rb.PushCopyObjects(broker->GetOutData().GetEvent());
160}
161
162void ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(HLERequestContext& ctx) {
163 LOG_DEBUG(Service_AM, "called");
164
165 IPC::ResponseBuilder rb{ctx, 2, 1};
166 rb.Push(ResultSuccess);
167 rb.PushCopyObjects(broker->GetInteractiveOutData().GetEvent());
168}
169
170void ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(HLERequestContext& ctx) {
171 LOG_WARNING(Service_AM, "(STUBBED) called");
172
173 // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
174 // actually used anywhere
175 constexpr u64 handle = 0xdeadbeef;
176
177 IPC::ResponseBuilder rb{ctx, 4};
178 rb.Push(ResultSuccess);
179 rb.Push(handle);
180}
181
182void ILibraryAppletAccessor::FrontendExecute() {
183 if (applet->frontend) {
184 applet->frontend->Initialize();
185 applet->frontend->Execute();
186 }
187}
188
189void ILibraryAppletAccessor::FrontendExecuteInteractive() {
190 if (applet->frontend) {
191 applet->frontend->ExecuteInteractive();
192 applet->frontend->Execute();
193 }
194}
195
196void ILibraryAppletAccessor::FrontendRequestExit() {
197 if (applet->frontend) {
198 applet->frontend->RequestExit();
199 }
200}
201
202} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class AppletDataBroker;
11struct Applet;
12
13class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
14public:
15 explicit ILibraryAppletAccessor(Core::System& system_,
16 std::shared_ptr<AppletDataBroker> broker_,
17 std::shared_ptr<Applet> applet_);
18 ~ILibraryAppletAccessor();
19
20protected:
21 void GetAppletStateChangedEvent(HLERequestContext& ctx);
22 void IsCompleted(HLERequestContext& ctx);
23 void GetResult(HLERequestContext& ctx);
24 void PresetLibraryAppletGpuTimeSliceZero(HLERequestContext& ctx);
25 void Start(HLERequestContext& ctx);
26 void RequestExit(HLERequestContext& ctx);
27 void PushInData(HLERequestContext& ctx);
28 void PopOutData(HLERequestContext& ctx);
29 void PushInteractiveInData(HLERequestContext& ctx);
30 void PopInteractiveOutData(HLERequestContext& ctx);
31 void GetPopOutDataEvent(HLERequestContext& ctx);
32 void GetPopInteractiveOutDataEvent(HLERequestContext& ctx);
33 void GetIndirectLayerConsumerHandle(HLERequestContext& ctx);
34
35 void FrontendExecute();
36 void FrontendExecuteInteractive();
37 void FrontendRequestExit();
38
39 const std::shared_ptr<AppletDataBroker> broker;
40 const std::shared_ptr<Applet> applet;
41};
42
43} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_transfer_memory.h"
5#include "core/hle/service/am/applet_data_broker.h"
6#include "core/hle/service/am/applet_manager.h"
7#include "core/hle/service/am/frontend/applets.h"
8#include "core/hle/service/am/library_applet_accessor.h"
9#include "core/hle/service/am/library_applet_creator.h"
10#include "core/hle/service/am/library_applet_storage.h"
11#include "core/hle/service/am/storage.h"
12#include "core/hle/service/ipc_helpers.h"
13#include "core/hle/service/sm/sm.h"
14
15namespace Service::AM {
16
17namespace {
18
19AppletProgramId AppletIdToProgramId(AppletId applet_id) {
20 switch (applet_id) {
21 case AppletId::OverlayDisplay:
22 return AppletProgramId::OverlayDisplay;
23 case AppletId::QLaunch:
24 return AppletProgramId::QLaunch;
25 case AppletId::Starter:
26 return AppletProgramId::Starter;
27 case AppletId::Auth:
28 return AppletProgramId::Auth;
29 case AppletId::Cabinet:
30 return AppletProgramId::Cabinet;
31 case AppletId::Controller:
32 return AppletProgramId::Controller;
33 case AppletId::DataErase:
34 return AppletProgramId::DataErase;
35 case AppletId::Error:
36 return AppletProgramId::Error;
37 case AppletId::NetConnect:
38 return AppletProgramId::NetConnect;
39 case AppletId::ProfileSelect:
40 return AppletProgramId::ProfileSelect;
41 case AppletId::SoftwareKeyboard:
42 return AppletProgramId::SoftwareKeyboard;
43 case AppletId::MiiEdit:
44 return AppletProgramId::MiiEdit;
45 case AppletId::Web:
46 return AppletProgramId::Web;
47 case AppletId::Shop:
48 return AppletProgramId::Shop;
49 case AppletId::PhotoViewer:
50 return AppletProgramId::PhotoViewer;
51 case AppletId::Settings:
52 return AppletProgramId::Settings;
53 case AppletId::OfflineWeb:
54 return AppletProgramId::OfflineWeb;
55 case AppletId::LoginShare:
56 return AppletProgramId::LoginShare;
57 case AppletId::WebAuth:
58 return AppletProgramId::WebAuth;
59 case AppletId::MyPage:
60 return AppletProgramId::MyPage;
61 default:
62 return static_cast<AppletProgramId>(0);
63 }
64}
65
66[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(
67 Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
68 LibraryAppletMode mode) {
69 const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
70 if (program_id == 0) {
71 // Unknown applet
72 return {};
73 }
74
75 auto process = std::make_unique<Process>(system);
76 if (!process->Initialize(program_id)) {
77 // Couldn't initialize the guest process
78 return {};
79 }
80
81 const auto applet = std::make_shared<Applet>(system, std::move(process));
82 applet->program_id = program_id;
83 applet->applet_id = applet_id;
84 applet->type = AppletType::LibraryApplet;
85 applet->library_applet_mode = mode;
86
87 // Set focus state
88 switch (mode) {
89 case LibraryAppletMode::AllForeground:
90 case LibraryAppletMode::NoUI:
91 applet->focus_state = FocusState::InFocus;
92 applet->hid_registration.EnableAppletToGetInput(true);
93 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
94 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
95 break;
96 case LibraryAppletMode::AllForegroundInitiallyHidden:
97 applet->system_buffer_manager.SetWindowVisibility(false);
98 applet->focus_state = FocusState::NotInFocus;
99 applet->hid_registration.EnableAppletToGetInput(false);
100 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
101 break;
102 case LibraryAppletMode::Background:
103 case LibraryAppletMode::BackgroundIndirectDisplay:
104 default:
105 applet->focus_state = FocusState::Background;
106 applet->hid_registration.EnableAppletToGetInput(true);
107 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
108 break;
109 }
110
111 auto broker = std::make_shared<AppletDataBroker>(system);
112 applet->caller_applet = caller_applet;
113 applet->caller_applet_broker = broker;
114
115 system.GetAppletManager().InsertApplet(applet);
116
117 return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
118}
119
120[[maybe_unused]] std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(
121 Core::System& system, std::shared_ptr<Applet> caller_applet, AppletId applet_id,
122 LibraryAppletMode mode) {
123 const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
124
125 auto process = std::make_unique<Process>(system);
126 auto applet = std::make_shared<Applet>(system, std::move(process));
127 applet->program_id = program_id;
128 applet->applet_id = applet_id;
129 applet->type = AppletType::LibraryApplet;
130 applet->library_applet_mode = mode;
131
132 auto storage = std::make_shared<AppletDataBroker>(system);
133 applet->caller_applet = caller_applet;
134 applet->caller_applet_broker = storage;
135 applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
136
137 return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
138}
139
140} // namespace
141
142ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_)
143 : ServiceFramework{system_, "ILibraryAppletCreator"}, applet{std::move(applet_)} {
144 static const FunctionInfo functions[] = {
145 {0, &ILibraryAppletCreator::CreateLibraryApplet, "CreateLibraryApplet"},
146 {1, nullptr, "TerminateAllLibraryApplets"},
147 {2, nullptr, "AreAnyLibraryAppletsLeft"},
148 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
149 {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
150 {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
151 };
152 RegisterHandlers(functions);
153}
154
155ILibraryAppletCreator::~ILibraryAppletCreator() = default;
156
157void ILibraryAppletCreator::CreateLibraryApplet(HLERequestContext& ctx) {
158 IPC::RequestParser rp{ctx};
159
160 const auto applet_id = rp.PopRaw<AppletId>();
161 const auto applet_mode = rp.PopRaw<LibraryAppletMode>();
162
163 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
164 applet_mode);
165
166 auto library_applet = CreateFrontendApplet(system, applet, applet_id, applet_mode);
167 if (!library_applet) {
168 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
169
170 IPC::ResponseBuilder rb{ctx, 2};
171 rb.Push(ResultUnknown);
172 return;
173 }
174
175 // Applet is created, can now be launched.
176 applet->library_applet_launchable_event.Signal();
177
178 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
179 rb.Push(ResultSuccess);
180 rb.PushIpcInterface<ILibraryAppletAccessor>(library_applet);
181}
182
183void ILibraryAppletCreator::CreateStorage(HLERequestContext& ctx) {
184 IPC::RequestParser rp{ctx};
185
186 const s64 size{rp.Pop<s64>()};
187
188 LOG_DEBUG(Service_AM, "called, size={}", size);
189
190 if (size <= 0) {
191 LOG_ERROR(Service_AM, "size is less than or equal to 0");
192 IPC::ResponseBuilder rb{ctx, 2};
193 rb.Push(ResultUnknown);
194 return;
195 }
196
197 std::vector<u8> data(size);
198
199 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
200 rb.Push(ResultSuccess);
201 rb.PushIpcInterface<IStorage>(system, AM::CreateStorage(std::move(data)));
202}
203
204void ILibraryAppletCreator::CreateTransferMemoryStorage(HLERequestContext& ctx) {
205 IPC::RequestParser rp{ctx};
206
207 struct Parameters {
208 bool is_writable;
209 s64 size;
210 };
211
212 const auto params{rp.PopRaw<Parameters>()};
213 const auto handle{ctx.GetCopyHandle(0)};
214
215 LOG_DEBUG(Service_AM, "called, is_writable={}, size={}, handle={:08X}", params.is_writable,
216 params.size, handle);
217
218 if (params.size <= 0) {
219 LOG_ERROR(Service_AM, "size is less than or equal to 0");
220 IPC::ResponseBuilder rb{ctx, 2};
221 rb.Push(ResultUnknown);
222 return;
223 }
224
225 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
226
227 if (transfer_mem.IsNull()) {
228 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
229 IPC::ResponseBuilder rb{ctx, 2};
230 rb.Push(ResultUnknown);
231 return;
232 }
233
234 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
235 rb.Push(ResultSuccess);
236 rb.PushIpcInterface<IStorage>(
237 system, AM::CreateTransferMemoryStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(),
238 params.is_writable, params.size));
239}
240
241void ILibraryAppletCreator::CreateHandleStorage(HLERequestContext& ctx) {
242 IPC::RequestParser rp{ctx};
243
244 const s64 size{rp.Pop<s64>()};
245 const auto handle{ctx.GetCopyHandle(0)};
246
247 LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
248
249 if (size <= 0) {
250 LOG_ERROR(Service_AM, "size is less than or equal to 0");
251 IPC::ResponseBuilder rb{ctx, 2};
252 rb.Push(ResultUnknown);
253 return;
254 }
255
256 auto transfer_mem = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(handle);
257
258 if (transfer_mem.IsNull()) {
259 LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
260 IPC::ResponseBuilder rb{ctx, 2};
261 rb.Push(ResultUnknown);
262 return;
263 }
264
265 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
266 rb.Push(ResultSuccess);
267 rb.PushIpcInterface<IStorage>(
268 system, AM::CreateHandleStorage(ctx.GetMemory(), transfer_mem.GetPointerUnsafe(), size));
269}
270
271} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
13public:
14 explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~ILibraryAppletCreator() override;
16
17private:
18 void CreateLibraryApplet(HLERequestContext& ctx);
19 void CreateStorage(HLERequestContext& ctx);
20 void CreateTransferMemoryStorage(HLERequestContext& ctx);
21 void CreateHandleStorage(HLERequestContext& ctx);
22
23 const std::shared_ptr<Applet> applet;
24};
25
26} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet_common_functions.h"
5#include "core/hle/service/am/audio_controller.h"
6#include "core/hle/service/am/common_state_getter.h"
7#include "core/hle/service/am/debug_functions.h"
8#include "core/hle/service/am/display_controller.h"
9#include "core/hle/service/am/global_state_controller.h"
10#include "core/hle/service/am/home_menu_functions.h"
11#include "core/hle/service/am/library_applet_creator.h"
12#include "core/hle/service/am/library_applet_proxy.h"
13#include "core/hle/service/am/library_applet_self_accessor.h"
14#include "core/hle/service/am/process_winding_controller.h"
15#include "core/hle/service/am/self_controller.h"
16#include "core/hle/service/am/window_controller.h"
17#include "core/hle/service/ipc_helpers.h"
18
19namespace Service::AM {
20
21ILibraryAppletProxy::ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
22 std::shared_ptr<Applet> applet_, Core::System& system_)
23 : ServiceFramework{system_, "ILibraryAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
24 applet_)} {
25 // clang-format off
26 static const FunctionInfo functions[] = {
27 {0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
28 {1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
29 {2, &ILibraryAppletProxy::GetWindowController, "GetWindowController"},
30 {3, &ILibraryAppletProxy::GetAudioController, "GetAudioController"},
31 {4, &ILibraryAppletProxy::GetDisplayController, "GetDisplayController"},
32 {10, &ILibraryAppletProxy::GetProcessWindingController, "GetProcessWindingController"},
33 {11, &ILibraryAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
34 {20, &ILibraryAppletProxy::OpenLibraryAppletSelfAccessor, "OpenLibraryAppletSelfAccessor"},
35 {21, &ILibraryAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
36 {22, &ILibraryAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
37 {23, &ILibraryAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
38 {1000, &ILibraryAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
39 };
40 // clang-format on
41
42 RegisterHandlers(functions);
43}
44
45ILibraryAppletProxy::~ILibraryAppletProxy() = default;
46
47void ILibraryAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) {
48 LOG_DEBUG(Service_AM, "called");
49
50 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
51 rb.Push(ResultSuccess);
52 rb.PushIpcInterface<ICommonStateGetter>(system, applet);
53}
54
55void ILibraryAppletProxy::GetSelfController(HLERequestContext& ctx) {
56 LOG_DEBUG(Service_AM, "called");
57
58 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
59 rb.Push(ResultSuccess);
60 rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
61}
62
63void ILibraryAppletProxy::GetWindowController(HLERequestContext& ctx) {
64 LOG_DEBUG(Service_AM, "called");
65
66 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
67 rb.Push(ResultSuccess);
68 rb.PushIpcInterface<IWindowController>(system, applet);
69}
70
71void ILibraryAppletProxy::GetAudioController(HLERequestContext& ctx) {
72 LOG_DEBUG(Service_AM, "called");
73
74 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
75 rb.Push(ResultSuccess);
76 rb.PushIpcInterface<IAudioController>(system);
77}
78
79void ILibraryAppletProxy::GetDisplayController(HLERequestContext& ctx) {
80 LOG_DEBUG(Service_AM, "called");
81
82 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
83 rb.Push(ResultSuccess);
84 rb.PushIpcInterface<IDisplayController>(system, applet);
85}
86
87void ILibraryAppletProxy::GetProcessWindingController(HLERequestContext& ctx) {
88 LOG_DEBUG(Service_AM, "called");
89
90 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
91 rb.Push(ResultSuccess);
92 rb.PushIpcInterface<IProcessWindingController>(system, applet);
93}
94
95void ILibraryAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
96 LOG_DEBUG(Service_AM, "called");
97
98 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
99 rb.Push(ResultSuccess);
100 rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
101}
102
103void ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(HLERequestContext& ctx) {
104 LOG_DEBUG(Service_AM, "called");
105
106 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
107 rb.Push(ResultSuccess);
108 rb.PushIpcInterface<ILibraryAppletSelfAccessor>(system, applet);
109}
110
111void ILibraryAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) {
112 LOG_DEBUG(Service_AM, "called");
113
114 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
115 rb.Push(ResultSuccess);
116 rb.PushIpcInterface<IAppletCommonFunctions>(system, applet);
117}
118
119void ILibraryAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) {
120 LOG_DEBUG(Service_AM, "called");
121
122 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
123 rb.Push(ResultSuccess);
124 rb.PushIpcInterface<IHomeMenuFunctions>(system);
125}
126
127void ILibraryAppletProxy::GetGlobalStateController(HLERequestContext& ctx) {
128 LOG_DEBUG(Service_AM, "called");
129
130 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
131 rb.Push(ResultSuccess);
132 rb.PushIpcInterface<IGlobalStateController>(system);
133}
134
135void ILibraryAppletProxy::GetDebugFunctions(HLERequestContext& ctx) {
136 LOG_DEBUG(Service_AM, "called");
137
138 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
139 rb.Push(ResultSuccess);
140 rb.PushIpcInterface<IDebugFunctions>(system);
141}
142
143} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
13public:
14 explicit ILibraryAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
15 std::shared_ptr<Applet> applet_, Core::System& system_);
16 ~ILibraryAppletProxy();
17
18private:
19 void GetCommonStateGetter(HLERequestContext& ctx);
20 void GetSelfController(HLERequestContext& ctx);
21 void GetWindowController(HLERequestContext& ctx);
22 void GetAudioController(HLERequestContext& ctx);
23 void GetDisplayController(HLERequestContext& ctx);
24 void GetProcessWindingController(HLERequestContext& ctx);
25 void GetLibraryAppletCreator(HLERequestContext& ctx);
26 void OpenLibraryAppletSelfAccessor(HLERequestContext& ctx);
27 void GetAppletCommonFunctions(HLERequestContext& ctx);
28 void GetHomeMenuFunctions(HLERequestContext& ctx);
29 void GetGlobalStateController(HLERequestContext& ctx);
30 void GetDebugFunctions(HLERequestContext& ctx);
31
32 Nvnflinger::Nvnflinger& nvnflinger;
33 std::shared_ptr<Applet> applet;
34};
35
36} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5#include "core/core_timing.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
8#include "core/file_sys/registered_cache.h"
9#include "core/hle/service/acc/profile_manager.h"
10#include "core/hle/service/am/am_results.h"
11#include "core/hle/service/am/applet_data_broker.h"
12#include "core/hle/service/am/applet_manager.h"
13#include "core/hle/service/am/frontend/applet_cabinet.h"
14#include "core/hle/service/am/frontend/applet_controller.h"
15#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
16#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
17#include "core/hle/service/am/frontend/applets.h"
18#include "core/hle/service/am/library_applet_self_accessor.h"
19#include "core/hle/service/am/storage.h"
20#include "core/hle/service/ipc_helpers.h"
21#include "core/hle/service/ns/ns.h"
22#include "core/hle/service/sm/sm.h"
23#include "hid_core/hid_types.h"
24
25namespace Service::AM {
26
27namespace {
28
29AppletIdentityInfo GetCallerIdentity(std::shared_ptr<Applet> applet) {
30 if (const auto caller_applet = applet->caller_applet.lock(); caller_applet) {
31 // TODO: is this actually the application ID?
32 return {
33 .applet_id = caller_applet->applet_id,
34 .application_id = caller_applet->program_id,
35 };
36 } else {
37 return {
38 .applet_id = AppletId::QLaunch,
39 .application_id = 0x0100000000001000ull,
40 };
41 }
42}
43
44} // namespace
45
46ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_,
47 std::shared_ptr<Applet> applet_)
48 : ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, applet{std::move(applet_)},
49 broker{applet->caller_applet_broker} {
50 // clang-format off
51 static const FunctionInfo functions[] = {
52 {0, &ILibraryAppletSelfAccessor::PopInData, "PopInData"},
53 {1, &ILibraryAppletSelfAccessor::PushOutData, "PushOutData"},
54 {2, &ILibraryAppletSelfAccessor::PopInteractiveInData, "PopInteractiveInData"},
55 {3, &ILibraryAppletSelfAccessor::PushInteractiveOutData, "PushInteractiveOutData"},
56 {5, &ILibraryAppletSelfAccessor::GetPopInDataEvent, "GetPopInDataEvent"},
57 {6, &ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent, "GetPopInteractiveInDataEvent"},
58 {10, &ILibraryAppletSelfAccessor::ExitProcessAndReturn, "ExitProcessAndReturn"},
59 {11, &ILibraryAppletSelfAccessor::GetLibraryAppletInfo, "GetLibraryAppletInfo"},
60 {12, &ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo, "GetMainAppletIdentityInfo"},
61 {13, &ILibraryAppletSelfAccessor::CanUseApplicationCore, "CanUseApplicationCore"},
62 {14, &ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo, "GetCallerAppletIdentityInfo"},
63 {15, nullptr, "GetMainAppletApplicationControlProperty"},
64 {16, nullptr, "GetMainAppletStorageId"},
65 {17, nullptr, "GetCallerAppletIdentityInfoStack"},
66 {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
67 {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"},
68 {20, nullptr, "PopExtraStorage"},
69 {25, nullptr, "GetPopExtraStorageEvent"},
70 {30, nullptr, "UnpopInData"},
71 {31, nullptr, "UnpopExtraStorage"},
72 {40, nullptr, "GetIndirectLayerProducerHandle"},
73 {50, nullptr, "ReportVisibleError"},
74 {51, nullptr, "ReportVisibleErrorWithErrorContext"},
75 {60, &ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage, "GetMainAppletApplicationDesiredLanguage"},
76 {70, &ILibraryAppletSelfAccessor::GetCurrentApplicationId, "GetCurrentApplicationId"},
77 {80, nullptr, "RequestExitToSelf"},
78 {90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
79 {100, nullptr, "CreateGameMovieTrimmer"},
80 {101, nullptr, "ReserveResourceForMovieOperation"},
81 {102, nullptr, "UnreserveResourceForMovieOperation"},
82 {110, &ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers, "GetMainAppletAvailableUsers"},
83 {120, nullptr, "GetLaunchStorageInfoForDebug"},
84 {130, nullptr, "GetGpuErrorDetectedSystemEvent"},
85 {140, nullptr, "SetApplicationMemoryReservation"},
86 {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"},
87 {160, &ILibraryAppletSelfAccessor::Cmd160, "Cmd160"},
88 };
89 // clang-format on
90 RegisterHandlers(functions);
91}
92
93ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
94
95void ILibraryAppletSelfAccessor::PopInData(HLERequestContext& ctx) {
96 LOG_INFO(Service_AM, "called");
97
98 std::shared_ptr<IStorage> data;
99 const auto res = broker->GetInData().Pop(&data);
100
101 if (res.IsSuccess()) {
102 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
103 rb.Push(res);
104 rb.PushIpcInterface(std::move(data));
105 } else {
106 IPC::ResponseBuilder rb{ctx, 2};
107 rb.Push(res);
108 }
109}
110
111void ILibraryAppletSelfAccessor::PushOutData(HLERequestContext& ctx) {
112 LOG_INFO(Service_AM, "called");
113
114 IPC::RequestParser rp{ctx};
115 broker->GetOutData().Push(rp.PopIpcInterface<IStorage>().lock());
116
117 IPC::ResponseBuilder rb{ctx, 2};
118 rb.Push(ResultSuccess);
119}
120
121void ILibraryAppletSelfAccessor::PopInteractiveInData(HLERequestContext& ctx) {
122 LOG_INFO(Service_AM, "called");
123
124 std::shared_ptr<IStorage> data;
125 const auto res = broker->GetInteractiveInData().Pop(&data);
126
127 if (res.IsSuccess()) {
128 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
129 rb.Push(res);
130 rb.PushIpcInterface(std::move(data));
131 } else {
132 IPC::ResponseBuilder rb{ctx, 2};
133 rb.Push(res);
134 }
135}
136
137void ILibraryAppletSelfAccessor::PushInteractiveOutData(HLERequestContext& ctx) {
138 LOG_INFO(Service_AM, "called");
139
140 IPC::RequestParser rp{ctx};
141 broker->GetInteractiveOutData().Push(rp.PopIpcInterface<IStorage>().lock());
142
143 IPC::ResponseBuilder rb{ctx, 2};
144 rb.Push(ResultSuccess);
145}
146
147void ILibraryAppletSelfAccessor::GetPopInDataEvent(HLERequestContext& ctx) {
148 LOG_INFO(Service_AM, "called");
149
150 IPC::ResponseBuilder rb{ctx, 2, 1};
151 rb.Push(ResultSuccess);
152 rb.PushCopyObjects(broker->GetInData().GetEvent());
153}
154
155void ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(HLERequestContext& ctx) {
156 LOG_INFO(Service_AM, "called");
157
158 IPC::ResponseBuilder rb{ctx, 2, 1};
159 rb.Push(ResultSuccess);
160 rb.PushCopyObjects(broker->GetInteractiveInData().GetEvent());
161}
162
163void ILibraryAppletSelfAccessor::ExitProcessAndReturn(HLERequestContext& ctx) {
164 LOG_INFO(Service_AM, "called");
165
166 system.GetAppletManager().TerminateAndRemoveApplet(applet->aruid);
167 broker->SignalCompletion();
168
169 IPC::ResponseBuilder rb{ctx, 2};
170 rb.Push(ResultSuccess);
171}
172
173void ILibraryAppletSelfAccessor::GetLibraryAppletInfo(HLERequestContext& ctx) {
174 struct LibraryAppletInfo {
175 AppletId applet_id;
176 LibraryAppletMode library_applet_mode;
177 };
178
179 LOG_WARNING(Service_AM, "(STUBBED) called");
180
181 const LibraryAppletInfo applet_info{
182 .applet_id = applet->applet_id,
183 .library_applet_mode = applet->library_applet_mode,
184 };
185
186 IPC::ResponseBuilder rb{ctx, 4};
187 rb.Push(ResultSuccess);
188 rb.PushRaw(applet_info);
189}
190
191void ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(HLERequestContext& ctx) {
192 LOG_WARNING(Service_AM, "(STUBBED) called");
193
194 const AppletIdentityInfo applet_info{
195 .applet_id = AppletId::QLaunch,
196 .application_id = 0x0100000000001000ull,
197 };
198
199 IPC::ResponseBuilder rb{ctx, 6};
200 rb.Push(ResultSuccess);
201 rb.PushRaw(applet_info);
202}
203
204void ILibraryAppletSelfAccessor::CanUseApplicationCore(HLERequestContext& ctx) {
205 LOG_WARNING(Service_AM, "(STUBBED) called");
206
207 // TODO: This appears to read the NPDM from state and check the core mask of the applet.
208 IPC::ResponseBuilder rb{ctx, 3};
209 rb.Push(ResultSuccess);
210 rb.Push<u8>(0);
211}
212
213void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& ctx) {
214 LOG_WARNING(Service_AM, "(STUBBED) called");
215
216 IPC::ResponseBuilder rb{ctx, 6};
217 rb.Push(ResultSuccess);
218 rb.PushRaw(GetCallerIdentity(applet));
219}
220
221void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) {
222 LOG_WARNING(Service_AM, "(STUBBED) called");
223
224 IPC::ResponseBuilder rb{ctx, 3};
225 rb.Push(ResultSuccess);
226 rb.Push<u32>(0);
227}
228
229void ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx) {
230 // FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage
231 auto identity = GetCallerIdentity(applet);
232
233 // TODO(bunnei): This should be configurable
234 LOG_DEBUG(Service_AM, "called");
235
236 // Get supported languages from NACP, if possible
237 // Default to 0 (all languages supported)
238 u32 supported_languages = 0;
239
240 const auto res = [this, identity] {
241 const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(),
242 system.GetContentProvider()};
243 auto metadata = pm.GetControlMetadata();
244 if (metadata.first != nullptr) {
245 return metadata;
246 }
247
248 const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id),
249 system.GetFileSystemController(),
250 system.GetContentProvider()};
251 return pm_update.GetControlMetadata();
252 }();
253
254 if (res.first != nullptr) {
255 supported_languages = res.first->GetSupportedLanguages();
256 }
257
258 // Call IApplicationManagerInterface implementation.
259 auto& service_manager = system.ServiceManager();
260 auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
261 auto app_man = ns_am2->GetApplicationManagerInterface();
262
263 // Get desired application language
264 u8 desired_language{};
265 const auto res_lang =
266 app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages);
267 if (res_lang != ResultSuccess) {
268 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(res_lang);
270 return;
271 }
272
273 // Convert to settings language code.
274 u64 language_code{};
275 const auto res_code =
276 app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language);
277 if (res_code != ResultSuccess) {
278 IPC::ResponseBuilder rb{ctx, 2};
279 rb.Push(res_code);
280 return;
281 }
282
283 LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
284
285 IPC::ResponseBuilder rb{ctx, 4};
286 rb.Push(ResultSuccess);
287 rb.Push(language_code);
288}
289
290void ILibraryAppletSelfAccessor::GetCurrentApplicationId(HLERequestContext& ctx) {
291 LOG_WARNING(Service_AM, "(STUBBED) called");
292
293 u64 application_id = 0;
294 if (auto caller_applet = applet->caller_applet.lock(); caller_applet) {
295 application_id = caller_applet->program_id;
296 }
297
298 IPC::ResponseBuilder rb{ctx, 4};
299 rb.Push(ResultSuccess);
300 rb.Push(application_id);
301}
302
303void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) {
304 const Service::Account::ProfileManager manager{};
305 bool is_empty{true};
306 s32 user_count{-1};
307
308 LOG_INFO(Service_AM, "called");
309
310 if (manager.GetUserCount() > 0) {
311 is_empty = false;
312 user_count = static_cast<s32>(manager.GetUserCount());
313 ctx.WriteBuffer(manager.GetAllUsers());
314 }
315
316 IPC::ResponseBuilder rb{ctx, 4};
317 rb.Push(ResultSuccess);
318 rb.Push<u8>(is_empty);
319 rb.Push(user_count);
320}
321
322void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) {
323 LOG_WARNING(Service_AM, "(STUBBED) called");
324
325 IPC::ResponseBuilder rb{ctx, 3};
326 rb.Push(ResultSuccess);
327 rb.Push<u8>(0);
328}
329
330void ILibraryAppletSelfAccessor::Cmd160(HLERequestContext& ctx) {
331 LOG_WARNING(Service_AM, "(STUBBED) called");
332
333 IPC::ResponseBuilder rb{ctx, 4};
334 rb.Push(ResultSuccess);
335 rb.Push<u64>(0);
336}
337
338} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <deque>
7#include <vector>
8
9#include "core/hle/service/service.h"
10
11namespace Service::AM {
12
13class AppletDataBroker;
14struct Applet;
15
16class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
17public:
18 explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet_);
19 ~ILibraryAppletSelfAccessor() override;
20
21private:
22 void PopInData(HLERequestContext& ctx);
23 void PushOutData(HLERequestContext& ctx);
24 void PopInteractiveInData(HLERequestContext& ctx);
25 void PushInteractiveOutData(HLERequestContext& ctx);
26 void GetPopInDataEvent(HLERequestContext& ctx);
27 void GetPopInteractiveInDataEvent(HLERequestContext& ctx);
28 void GetLibraryAppletInfo(HLERequestContext& ctx);
29 void GetMainAppletIdentityInfo(HLERequestContext& ctx);
30 void CanUseApplicationCore(HLERequestContext& ctx);
31 void ExitProcessAndReturn(HLERequestContext& ctx);
32 void GetCallerAppletIdentityInfo(HLERequestContext& ctx);
33 void GetDesirableKeyboardLayout(HLERequestContext& ctx);
34 void GetMainAppletApplicationDesiredLanguage(HLERequestContext& ctx);
35 void GetCurrentApplicationId(HLERequestContext& ctx);
36 void GetMainAppletAvailableUsers(HLERequestContext& ctx);
37 void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx);
38 void Cmd160(HLERequestContext& ctx);
39
40 const std::shared_ptr<Applet> applet;
41 const std::shared_ptr<AppletDataBroker> broker;
42};
43
44} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_storage.cpp b/src/core/hle/service/am/library_applet_storage.cpp
new file mode 100644
index 000000000..46e6c0111
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_storage.cpp
@@ -0,0 +1,140 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_transfer_memory.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/library_applet_storage.h"
7#include "core/memory.h"
8
9namespace Service::AM {
10
11namespace {
12
13Result ValidateOffset(s64 offset, size_t size, size_t data_size) {
14 R_UNLESS(offset >= 0, AM::ResultInvalidOffset);
15
16 const size_t begin = offset;
17 const size_t end = begin + size;
18
19 R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset);
20 R_SUCCEED();
21}
22
23class BufferLibraryAppletStorage final : public LibraryAppletStorage {
24public:
25 explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {}
26 ~BufferLibraryAppletStorage() = default;
27
28 Result Read(s64 offset, void* buffer, size_t size) override {
29 R_TRY(ValidateOffset(offset, size, m_data.size()));
30
31 std::memcpy(buffer, m_data.data() + offset, size);
32
33 R_SUCCEED();
34 }
35
36 Result Write(s64 offset, const void* buffer, size_t size) override {
37 R_TRY(ValidateOffset(offset, size, m_data.size()));
38
39 std::memcpy(m_data.data() + offset, buffer, size);
40
41 R_SUCCEED();
42 }
43
44 s64 GetSize() override {
45 return m_data.size();
46 }
47
48 Kernel::KTransferMemory* GetHandle() override {
49 return nullptr;
50 }
51
52private:
53 std::vector<u8> m_data;
54};
55
56class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage {
57public:
58 explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory,
59 Kernel::KTransferMemory* trmem, bool is_writable,
60 s64 size)
61 : m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) {
62 m_trmem->Open();
63 }
64
65 ~TransferMemoryLibraryAppletStorage() {
66 m_trmem->Close();
67 m_trmem = nullptr;
68 }
69
70 Result Read(s64 offset, void* buffer, size_t size) override {
71 R_TRY(ValidateOffset(offset, size, m_size));
72
73 m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size);
74
75 R_SUCCEED();
76 }
77
78 Result Write(s64 offset, const void* buffer, size_t size) override {
79 R_UNLESS(m_is_writable, ResultUnknown);
80 R_TRY(ValidateOffset(offset, size, m_size));
81
82 m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size);
83
84 R_SUCCEED();
85 }
86
87 s64 GetSize() override {
88 return m_size;
89 }
90
91 Kernel::KTransferMemory* GetHandle() override {
92 return nullptr;
93 }
94
95protected:
96 Core::Memory::Memory& m_memory;
97 Kernel::KTransferMemory* m_trmem;
98 bool m_is_writable;
99 s64 m_size;
100};
101
102class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage {
103public:
104 explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory,
105 Kernel::KTransferMemory* trmem, s64 size)
106 : TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {}
107 ~HandleLibraryAppletStorage() = default;
108
109 Kernel::KTransferMemory* GetHandle() override {
110 return m_trmem;
111 }
112};
113
114} // namespace
115
116LibraryAppletStorage::~LibraryAppletStorage() = default;
117
118std::vector<u8> LibraryAppletStorage::GetData() {
119 std::vector<u8> data(this->GetSize());
120 this->Read(0, data.data(), data.size());
121 return data;
122}
123
124std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) {
125 return std::make_shared<BufferLibraryAppletStorage>(std::move(data));
126}
127
128std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
129 Kernel::KTransferMemory* trmem,
130 bool is_writable, s64 size) {
131 return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size);
132}
133
134std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
135 Kernel::KTransferMemory* trmem,
136 s64 size) {
137 return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size);
138}
139
140} // namespace Service::AM
diff --git a/src/core/hle/service/am/library_applet_storage.h b/src/core/hle/service/am/library_applet_storage.h
new file mode 100644
index 000000000..7f53f3a9c
--- /dev/null
+++ b/src/core/hle/service/am/library_applet_storage.h
@@ -0,0 +1,36 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Core::Memory {
9class Memory;
10}
11
12namespace Kernel {
13class KTransferMemory;
14}
15
16namespace Service::AM {
17
18class LibraryAppletStorage {
19public:
20 virtual ~LibraryAppletStorage();
21 virtual Result Read(s64 offset, void* buffer, size_t size) = 0;
22 virtual Result Write(s64 offset, const void* buffer, size_t size) = 0;
23 virtual s64 GetSize() = 0;
24 virtual Kernel::KTransferMemory* GetHandle() = 0;
25
26 std::vector<u8> GetData();
27};
28
29std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data);
30std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory,
31 Kernel::KTransferMemory* trmem,
32 bool is_writable, s64 size);
33std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory,
34 Kernel::KTransferMemory* trmem, s64 size);
35
36} // namespace Service::AM
diff --git a/src/core/hle/service/am/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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/lock_accessor.h"
5#include "core/hle/service/ipc_helpers.h"
6
7namespace Service::AM {
8
9ILockAccessor::ILockAccessor(Core::System& system_)
10 : ServiceFramework{system_, "ILockAccessor"}, service_context{system_, "ILockAccessor"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {1, &ILockAccessor::TryLock, "TryLock"},
14 {2, &ILockAccessor::Unlock, "Unlock"},
15 {3, &ILockAccessor::GetEvent, "GetEvent"},
16 {4,&ILockAccessor::IsLocked, "IsLocked"},
17 };
18 // clang-format on
19
20 RegisterHandlers(functions);
21
22 lock_event = service_context.CreateEvent("ILockAccessor::LockEvent");
23}
24
25ILockAccessor::~ILockAccessor() {
26 service_context.CloseEvent(lock_event);
27};
28
29void ILockAccessor::TryLock(HLERequestContext& ctx) {
30 IPC::RequestParser rp{ctx};
31 const auto return_handle = rp.Pop<bool>();
32
33 LOG_WARNING(Service_AM, "(STUBBED) called, return_handle={}", return_handle);
34
35 // TODO: When return_handle is true this function should return the lock handle
36
37 is_locked = true;
38
39 IPC::ResponseBuilder rb{ctx, 3};
40 rb.Push(ResultSuccess);
41 rb.Push<u8>(is_locked);
42}
43
44void ILockAccessor::Unlock(HLERequestContext& ctx) {
45 LOG_INFO(Service_AM, "called");
46
47 is_locked = false;
48
49 IPC::ResponseBuilder rb{ctx, 2};
50 rb.Push(ResultSuccess);
51}
52
53void ILockAccessor::GetEvent(HLERequestContext& ctx) {
54 LOG_INFO(Service_AM, "called");
55
56 lock_event->Signal();
57
58 IPC::ResponseBuilder rb{ctx, 2, 1};
59 rb.Push(ResultSuccess);
60 rb.PushCopyObjects(lock_event->GetReadableEvent());
61}
62
63void ILockAccessor::IsLocked(HLERequestContext& ctx) {
64 LOG_INFO(Service_AM, "called");
65
66 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(ResultSuccess);
68 rb.Push<u8>(is_locked);
69}
70
71} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11class ILockAccessor final : public ServiceFramework<ILockAccessor> {
12public:
13 explicit ILockAccessor(Core::System& system_);
14 ~ILockAccessor() override;
15
16private:
17 void TryLock(HLERequestContext& ctx);
18 void Unlock(HLERequestContext& ctx);
19 void GetEvent(HLERequestContext& ctx);
20 void IsLocked(HLERequestContext& ctx);
21
22 bool is_locked{};
23
24 Kernel::KEvent* lock_event;
25 KernelHelpers::ServiceContext service_context;
26};
27
28} // namespace Service::AM
diff --git a/src/core/hle/service/am/managed_layer_holder.cpp b/src/core/hle/service/am/managed_layer_holder.cpp
new file mode 100644
index 000000000..61eb8641a
--- /dev/null
+++ b/src/core/hle/service/am/managed_layer_holder.cpp
@@ -0,0 +1,59 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/managed_layer_holder.h"
5#include "core/hle/service/nvnflinger/nvnflinger.h"
6
7namespace Service::AM {
8
9ManagedLayerHolder::ManagedLayerHolder() = default;
10ManagedLayerHolder::~ManagedLayerHolder() {
11 if (!m_nvnflinger) {
12 return;
13 }
14
15 for (const auto& layer : m_managed_display_layers) {
16 m_nvnflinger->DestroyLayer(layer);
17 }
18
19 for (const auto& layer : m_managed_display_recording_layers) {
20 m_nvnflinger->DestroyLayer(layer);
21 }
22
23 m_nvnflinger = nullptr;
24}
25
26void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) {
27 m_nvnflinger = nvnflinger;
28}
29
30void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) {
31 // TODO(Subv): Find out how AM determines the display to use, for now just
32 // create the layer in the Default display.
33 const auto display_id = m_nvnflinger->OpenDisplay("Default");
34 const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
35
36 m_managed_display_layers.emplace(*layer_id);
37
38 *out_layer = *layer_id;
39}
40
41void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer,
42 u64* out_recording_layer) {
43 // TODO(Subv): Find out how AM determines the display to use, for now just
44 // create the layer in the Default display.
45 // This calls nn::vi::CreateRecordingLayer() which creates another layer.
46 // Currently we do not support more than 1 layer per display, output 1 layer id for now.
47 // Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
48 // side effects.
49 // TODO: Support multiple layers
50 const auto display_id = m_nvnflinger->OpenDisplay("Default");
51 const auto layer_id = m_nvnflinger->CreateLayer(*display_id);
52
53 m_managed_display_layers.emplace(*layer_id);
54
55 *out_layer = *layer_id;
56 *out_recording_layer = 0;
57}
58
59} // namespace Service::AM
diff --git a/src/core/hle/service/am/managed_layer_holder.h b/src/core/hle/service/am/managed_layer_holder.h
new file mode 100644
index 000000000..f7fe03f24
--- /dev/null
+++ b/src/core/hle/service/am/managed_layer_holder.h
@@ -0,0 +1,32 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11namespace Service::Nvnflinger {
12class Nvnflinger;
13}
14
15namespace Service::AM {
16
17class ManagedLayerHolder {
18public:
19 ManagedLayerHolder();
20 ~ManagedLayerHolder();
21
22 void Initialize(Nvnflinger::Nvnflinger* nvnflinger);
23 void CreateManagedDisplayLayer(u64* out_layer);
24 void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer);
25
26private:
27 Nvnflinger::Nvnflinger* m_nvnflinger{};
28 std::set<u64> m_managed_display_layers{};
29 std::set<u64> m_managed_display_recording_layers{};
30};
31
32} // namespace Service::AM
diff --git a/src/core/hle/service/am/process.cpp b/src/core/hle/service/am/process.cpp
new file mode 100644
index 000000000..16b685f86
--- /dev/null
+++ b/src/core/hle/service/am/process.cpp
@@ -0,0 +1,138 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/scope_exit.h"
5
6#include "core/file_sys/nca_metadata.h"
7#include "core/file_sys/registered_cache.h"
8#include "core/hle/kernel/k_process.h"
9#include "core/hle/service/am/process.h"
10#include "core/hle/service/filesystem/filesystem.h"
11#include "core/loader/loader.h"
12
13namespace Service::AM {
14
15Process::Process(Core::System& system)
16 : m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(),
17 m_program_id(), m_process_started() {}
18
19Process::~Process() {
20 this->Finalize();
21}
22
23bool Process::Initialize(u64 program_id) {
24 // First, ensure we are not holding another process.
25 this->Finalize();
26
27 // Get the filesystem controller.
28 auto& fsc = m_system.GetFileSystemController();
29
30 // Attempt to load program NCA.
31 const FileSys::RegisteredCache* bis_system{};
32 FileSys::VirtualFile nca{};
33
34 // Get the program NCA from built-in storage.
35 bis_system = fsc.GetSystemNANDContents();
36 if (bis_system) {
37 nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
38 }
39
40 // Ensure we retrieved a program NCA.
41 if (!nca) {
42 return false;
43 }
44
45 // Get the appropriate loader to parse this NCA.
46 auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0);
47
48 // Ensure we have a loader which can parse the NCA.
49 if (!app_loader) {
50 return false;
51 }
52
53 // Create the process.
54 auto* const process = Kernel::KProcess::Create(m_system.Kernel());
55 Kernel::KProcess::Register(m_system.Kernel(), process);
56
57 // On exit, ensure we free the additional reference to the process.
58 SCOPE_EXIT({ process->Close(); });
59
60 // Insert process modules into memory.
61 const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
62
63 // Ensure loading was successful.
64 if (load_result != Loader::ResultStatus::Success) {
65 return false;
66 }
67
68 // TODO: remove this, kernel already tracks this
69 m_system.Kernel().AppendNewProcess(process);
70
71 // Note the load parameters from NPDM.
72 m_main_thread_priority = load_parameters->main_thread_priority;
73 m_main_thread_stack_size = load_parameters->main_thread_stack_size;
74
75 // This process has not started yet.
76 m_process_started = false;
77
78 // Take ownership of the process object.
79 m_process = process;
80 m_process->Open();
81
82 // We succeeded.
83 return true;
84}
85
86void Process::Finalize() {
87 // Terminate, if we are currently holding a process.
88 this->Terminate();
89
90 // Close the process.
91 if (m_process) {
92 m_process->Close();
93
94 // TODO: remove this, kernel already tracks this
95 m_system.Kernel().RemoveProcess(m_process);
96 }
97
98 // Clean up.
99 m_process = nullptr;
100 m_main_thread_priority = 0;
101 m_main_thread_stack_size = 0;
102 m_program_id = 0;
103 m_process_started = false;
104}
105
106bool Process::Run() {
107 // If we already started the process, don't start again.
108 if (m_process_started) {
109 return false;
110 }
111
112 // Start.
113 if (m_process) {
114 m_process->Run(m_main_thread_priority, m_main_thread_stack_size);
115 }
116
117 // Mark as started.
118 m_process_started = true;
119
120 // We succeeded.
121 return true;
122}
123
124void Process::Terminate() {
125 if (m_process) {
126 m_process->Terminate();
127 }
128}
129
130u64 Process::GetProcessId() const {
131 if (m_process) {
132 return m_process->GetProcessId();
133 }
134
135 return 0;
136}
137
138} // namespace Service::AM
diff --git a/src/core/hle/service/am/process.h b/src/core/hle/service/am/process.h
new file mode 100644
index 000000000..4b908ade4
--- /dev/null
+++ b/src/core/hle/service/am/process.h
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8
9namespace Kernel {
10class KProcess;
11}
12
13namespace Core {
14class System;
15}
16
17namespace Service::AM {
18
19class Process {
20public:
21 explicit Process(Core::System& system);
22 ~Process();
23
24 bool Initialize(u64 program_id);
25 void Finalize();
26
27 bool Run();
28 void Terminate();
29
30 bool IsInitialized() const {
31 return m_process != nullptr;
32 }
33 u64 GetProcessId() const;
34 u64 GetProgramId() const {
35 return m_program_id;
36 }
37 Kernel::KProcess* GetProcess() const {
38 return m_process;
39 }
40
41private:
42 Core::System& m_system;
43 Kernel::KProcess* m_process{};
44 s32 m_main_thread_priority{};
45 u64 m_main_thread_stack_size{};
46 u64 m_program_id{};
47 bool m_process_started{};
48};
49
50} // namespace Service::AM
diff --git a/src/core/hle/service/am/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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/frontend/applets.h"
5#include "core/hle/service/am/library_applet_accessor.h"
6#include "core/hle/service/am/process_winding_controller.h"
7#include "core/hle/service/ipc_helpers.h"
8
9namespace Service::AM {
10
11IProcessWindingController::IProcessWindingController(Core::System& system_,
12 std::shared_ptr<Applet> applet_)
13 : ServiceFramework{system_, "IProcessWindingController"}, applet{std::move(applet_)} {
14 // clang-format off
15 static const FunctionInfo functions[] = {
16 {0, &IProcessWindingController::GetLaunchReason, "GetLaunchReason"},
17 {11, &IProcessWindingController::OpenCallingLibraryApplet, "OpenCallingLibraryApplet"},
18 {21, nullptr, "PushContext"},
19 {22, nullptr, "PopContext"},
20 {23, nullptr, "CancelWindingReservation"},
21 {30, nullptr, "WindAndDoReserved"},
22 {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
23 {41, nullptr, "ReserveToStartAndWait"},
24 };
25 // clang-format on
26
27 RegisterHandlers(functions);
28}
29
30IProcessWindingController::~IProcessWindingController() = default;
31
32void IProcessWindingController::GetLaunchReason(HLERequestContext& ctx) {
33 LOG_WARNING(Service_AM, "(STUBBED) called");
34
35 IPC::ResponseBuilder rb{ctx, 3};
36 rb.Push(ResultSuccess);
37 rb.PushRaw(applet->launch_reason);
38}
39
40void IProcessWindingController::OpenCallingLibraryApplet(HLERequestContext& ctx) {
41 const auto caller_applet = applet->caller_applet.lock();
42 if (caller_applet == nullptr) {
43 LOG_ERROR(Service_AM, "No calling applet available");
44
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(ResultUnknown);
47 return;
48 }
49
50 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
51 rb.Push(ResultSuccess);
52 rb.PushIpcInterface<ILibraryAppletAccessor>(system, applet->caller_applet_broker,
53 caller_applet);
54}
55
56} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
13public:
14 explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~IProcessWindingController() override;
16
17private:
18 void GetLaunchReason(HLERequestContext& ctx);
19 void OpenCallingLibraryApplet(HLERequestContext& ctx);
20
21 const std::shared_ptr<Applet> applet;
22};
23
24} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/am_results.h"
5#include "core/hle/service/am/frontend/applets.h"
6#include "core/hle/service/am/self_controller.h"
7#include "core/hle/service/caps/caps_su.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
10#include "core/hle/service/nvnflinger/nvnflinger.h"
11#include "core/hle/service/sm/sm.h"
12#include "core/hle/service/vi/vi_results.h"
13
14namespace Service::AM {
15
16ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_,
17 Nvnflinger::Nvnflinger& nvnflinger_)
18 : ServiceFramework{system_, "ISelfController"}, nvnflinger{nvnflinger_}, applet{std::move(
19 applet_)} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, &ISelfController::Exit, "Exit"},
23 {1, &ISelfController::LockExit, "LockExit"},
24 {2, &ISelfController::UnlockExit, "UnlockExit"},
25 {3, &ISelfController::EnterFatalSection, "EnterFatalSection"},
26 {4, &ISelfController::LeaveFatalSection, "LeaveFatalSection"},
27 {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
28 {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
29 {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
30 {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"},
31 {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
32 {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
33 {15, &ISelfController::SetScreenShotAppletIdentityInfo, "SetScreenShotAppletIdentityInfo"},
34 {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"},
35 {17, nullptr, "SetControllerFirmwareUpdateSection"},
36 {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
37 {19, &ISelfController::SetAlbumImageOrientation, "SetAlbumImageOrientation"},
38 {20, nullptr, "SetDesirableKeyboardLayout"},
39 {21, nullptr, "GetScreenShotProgramId"},
40 {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"},
41 {41, &ISelfController::IsSystemBufferSharingEnabled, "IsSystemBufferSharingEnabled"},
42 {42, &ISelfController::GetSystemSharedLayerHandle, "GetSystemSharedLayerHandle"},
43 {43, &ISelfController::GetSystemSharedBufferHandle, "GetSystemSharedBufferHandle"},
44 {44, &ISelfController::CreateManagedDisplaySeparableLayer, "CreateManagedDisplaySeparableLayer"},
45 {45, nullptr, "SetManagedDisplayLayerSeparationMode"},
46 {46, nullptr, "SetRecordingLayerCompositionEnabled"},
47 {50, &ISelfController::SetHandlesRequestToDisplay, "SetHandlesRequestToDisplay"},
48 {51, &ISelfController::ApproveToDisplay, "ApproveToDisplay"},
49 {60, nullptr, "OverrideAutoSleepTimeAndDimmingTime"},
50 {61, nullptr, "SetMediaPlaybackState"},
51 {62, &ISelfController::SetIdleTimeDetectionExtension, "SetIdleTimeDetectionExtension"},
52 {63, &ISelfController::GetIdleTimeDetectionExtension, "GetIdleTimeDetectionExtension"},
53 {64, nullptr, "SetInputDetectionSourceSet"},
54 {65, &ISelfController::ReportUserIsActive, "ReportUserIsActive"},
55 {66, nullptr, "GetCurrentIlluminance"},
56 {67, nullptr, "IsIlluminanceAvailable"},
57 {68, &ISelfController::SetAutoSleepDisabled, "SetAutoSleepDisabled"},
58 {69, &ISelfController::IsAutoSleepDisabled, "IsAutoSleepDisabled"},
59 {70, nullptr, "ReportMultimediaError"},
60 {71, nullptr, "GetCurrentIlluminanceEx"},
61 {72, nullptr, "SetInputDetectionPolicy"},
62 {80, nullptr, "SetWirelessPriorityMode"},
63 {90, &ISelfController::GetAccumulatedSuspendedTickValue, "GetAccumulatedSuspendedTickValue"},
64 {91, &ISelfController::GetAccumulatedSuspendedTickChangedEvent, "GetAccumulatedSuspendedTickChangedEvent"},
65 {100, &ISelfController::SetAlbumImageTakenNotificationEnabled, "SetAlbumImageTakenNotificationEnabled"},
66 {110, nullptr, "SetApplicationAlbumUserData"},
67 {120, &ISelfController::SaveCurrentScreenshot, "SaveCurrentScreenshot"},
68 {130, &ISelfController::SetRecordVolumeMuted, "SetRecordVolumeMuted"},
69 {1000, nullptr, "GetDebugStorageChannel"},
70 };
71 // clang-format on
72
73 RegisterHandlers(functions);
74}
75
76ISelfController::~ISelfController() = default;
77
78void ISelfController::Exit(HLERequestContext& ctx) {
79 LOG_DEBUG(Service_AM, "called");
80
81 IPC::ResponseBuilder rb{ctx, 2};
82 rb.Push(ResultSuccess);
83
84 // TODO
85 system.Exit();
86}
87
88void ISelfController::LockExit(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_AM, "called");
90
91 system.SetExitLocked(true);
92
93 IPC::ResponseBuilder rb{ctx, 2};
94 rb.Push(ResultSuccess);
95}
96
97void ISelfController::UnlockExit(HLERequestContext& ctx) {
98 LOG_DEBUG(Service_AM, "called");
99
100 system.SetExitLocked(false);
101
102 IPC::ResponseBuilder rb{ctx, 2};
103 rb.Push(ResultSuccess);
104
105 if (system.GetExitRequested()) {
106 system.Exit();
107 }
108}
109
110void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
111
112 std::scoped_lock lk{applet->lock};
113 applet->fatal_section_count++;
114 LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", applet->fatal_section_count);
115
116 IPC::ResponseBuilder rb{ctx, 2};
117 rb.Push(ResultSuccess);
118}
119
120void ISelfController::LeaveFatalSection(HLERequestContext& ctx) {
121 LOG_DEBUG(Service_AM, "called.");
122
123 // Entry and exit of fatal sections must be balanced.
124 std::scoped_lock lk{applet->lock};
125 if (applet->fatal_section_count == 0) {
126 IPC::ResponseBuilder rb{ctx, 2};
127 rb.Push(AM::ResultFatalSectionCountImbalance);
128 return;
129 }
130
131 applet->fatal_section_count--;
132
133 IPC::ResponseBuilder rb{ctx, 2};
134 rb.Push(ResultSuccess);
135}
136
137void ISelfController::GetLibraryAppletLaunchableEvent(HLERequestContext& ctx) {
138 LOG_WARNING(Service_AM, "(STUBBED) called");
139
140 applet->library_applet_launchable_event.Signal();
141
142 IPC::ResponseBuilder rb{ctx, 2, 1};
143 rb.Push(ResultSuccess);
144 rb.PushCopyObjects(applet->library_applet_launchable_event.GetHandle());
145}
146
147void ISelfController::SetScreenShotPermission(HLERequestContext& ctx) {
148 IPC::RequestParser rp{ctx};
149 const auto permission = rp.PopEnum<ScreenshotPermission>();
150 LOG_DEBUG(Service_AM, "called, permission={}", permission);
151
152 std::scoped_lock lk{applet->lock};
153 applet->screenshot_permission = permission;
154
155 IPC::ResponseBuilder rb{ctx, 2};
156 rb.Push(ResultSuccess);
157}
158
159void ISelfController::SetOperationModeChangedNotification(HLERequestContext& ctx) {
160 IPC::RequestParser rp{ctx};
161
162 const bool notification_enabled = rp.Pop<bool>();
163 LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled);
164
165 std::scoped_lock lk{applet->lock};
166 applet->operation_mode_changed_notification_enabled = notification_enabled;
167
168 IPC::ResponseBuilder rb{ctx, 2};
169 rb.Push(ResultSuccess);
170}
171
172void ISelfController::SetPerformanceModeChangedNotification(HLERequestContext& ctx) {
173 IPC::RequestParser rp{ctx};
174
175 const bool notification_enabled = rp.Pop<bool>();
176 LOG_WARNING(Service_AM, "(STUBBED) called notification_enabled={}", notification_enabled);
177
178 std::scoped_lock lk{applet->lock};
179 applet->performance_mode_changed_notification_enabled = notification_enabled;
180
181 IPC::ResponseBuilder rb{ctx, 2};
182 rb.Push(ResultSuccess);
183}
184
185void ISelfController::SetFocusHandlingMode(HLERequestContext& ctx) {
186 IPC::RequestParser rp{ctx};
187
188 const auto flags = rp.PopRaw<FocusHandlingMode>();
189
190 LOG_WARNING(Service_AM, "(STUBBED) called. unknown0={}, unknown1={}, unknown2={}",
191 flags.unknown0, flags.unknown1, flags.unknown2);
192
193 std::scoped_lock lk{applet->lock};
194 applet->focus_handling_mode = flags;
195
196 IPC::ResponseBuilder rb{ctx, 2};
197 rb.Push(ResultSuccess);
198}
199
200void ISelfController::SetRestartMessageEnabled(HLERequestContext& ctx) {
201 LOG_WARNING(Service_AM, "(STUBBED) called");
202
203 std::scoped_lock lk{applet->lock};
204 applet->restart_message_enabled = true;
205
206 IPC::ResponseBuilder rb{ctx, 2};
207 rb.Push(ResultSuccess);
208}
209
210void ISelfController::SetScreenShotAppletIdentityInfo(HLERequestContext& ctx) {
211 LOG_WARNING(Service_AM, "(STUBBED) called");
212
213 IPC::RequestParser rp{ctx};
214 std::scoped_lock lk{applet->lock};
215 applet->screen_shot_identity = rp.PopRaw<AppletIdentityInfo>();
216
217 IPC::ResponseBuilder rb{ctx, 2};
218 rb.Push(ResultSuccess);
219}
220
221void ISelfController::SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx) {
222 IPC::RequestParser rp{ctx};
223
224 const bool enabled = rp.Pop<bool>();
225 LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
226
227 std::scoped_lock lk{applet->lock};
228 ASSERT(applet->type == AppletType::Application);
229 applet->out_of_focus_suspension_enabled = enabled;
230
231 IPC::ResponseBuilder rb{ctx, 2};
232 rb.Push(ResultSuccess);
233}
234
235void ISelfController::SetAlbumImageOrientation(HLERequestContext& ctx) {
236 IPC::RequestParser rp{ctx};
237
238 const auto orientation = rp.PopRaw<Capture::AlbumImageOrientation>();
239 LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", static_cast<s32>(orientation));
240
241 std::scoped_lock lk{applet->lock};
242 applet->album_image_orientation = orientation;
243
244 IPC::ResponseBuilder rb{ctx, 2};
245 rb.Push(ResultSuccess);
246}
247
248void ISelfController::CreateManagedDisplayLayer(HLERequestContext& ctx) {
249 LOG_WARNING(Service_AM, "(STUBBED) called");
250
251 u64 layer_id{};
252 applet->managed_layer_holder.Initialize(&nvnflinger);
253 applet->managed_layer_holder.CreateManagedDisplayLayer(&layer_id);
254
255 IPC::ResponseBuilder rb{ctx, 4};
256 rb.Push(ResultSuccess);
257 rb.Push(layer_id);
258}
259
260void ISelfController::IsSystemBufferSharingEnabled(HLERequestContext& ctx) {
261 LOG_WARNING(Service_AM, "(STUBBED) called");
262
263 IPC::ResponseBuilder rb{ctx, 2};
264 rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
265}
266
267void ISelfController::GetSystemSharedLayerHandle(HLERequestContext& ctx) {
268 LOG_WARNING(Service_AM, "(STUBBED) called");
269
270 u64 buffer_id, layer_id;
271 applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id);
272
273 IPC::ResponseBuilder rb{ctx, 6};
274 rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
275 rb.Push<s64>(buffer_id);
276 rb.Push<s64>(layer_id);
277}
278
279void ISelfController::GetSystemSharedBufferHandle(HLERequestContext& ctx) {
280 LOG_WARNING(Service_AM, "(STUBBED) called");
281
282 u64 buffer_id, layer_id;
283 applet->system_buffer_manager.GetSystemSharedLayerHandle(&buffer_id, &layer_id);
284
285 IPC::ResponseBuilder rb{ctx, 4};
286 rb.Push(this->EnsureBufferSharingEnabled(ctx.GetThread().GetOwnerProcess()));
287 rb.Push<s64>(buffer_id);
288}
289
290Result ISelfController::EnsureBufferSharingEnabled(Kernel::KProcess* process) {
291 if (applet->system_buffer_manager.Initialize(&nvnflinger, process, applet->applet_id)) {
292 return ResultSuccess;
293 }
294
295 return VI::ResultOperationFailed;
296}
297
298void ISelfController::CreateManagedDisplaySeparableLayer(HLERequestContext& ctx) {
299 LOG_WARNING(Service_AM, "(STUBBED) called");
300
301 u64 layer_id{};
302 u64 recording_layer_id{};
303 applet->managed_layer_holder.Initialize(&nvnflinger);
304 applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(&layer_id, &recording_layer_id);
305
306 IPC::ResponseBuilder rb{ctx, 6};
307 rb.Push(ResultSuccess);
308 rb.Push(layer_id);
309 rb.Push(recording_layer_id);
310}
311
312void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) {
313 LOG_WARNING(Service_AM, "(STUBBED) called");
314
315 IPC::ResponseBuilder rb{ctx, 2};
316 rb.Push(ResultSuccess);
317}
318
319void ISelfController::ApproveToDisplay(HLERequestContext& ctx) {
320 LOG_WARNING(Service_AM, "(STUBBED) called");
321
322 IPC::ResponseBuilder rb{ctx, 2};
323 rb.Push(ResultSuccess);
324}
325
326void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) {
327 IPC::RequestParser rp{ctx};
328
329 const auto extension = rp.PopRaw<IdleTimeDetectionExtension>();
330 LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", extension);
331
332 std::scoped_lock lk{applet->lock};
333 applet->idle_time_detection_extension = extension;
334
335 IPC::ResponseBuilder rb{ctx, 2};
336 rb.Push(ResultSuccess);
337}
338
339void ISelfController::GetIdleTimeDetectionExtension(HLERequestContext& ctx) {
340 LOG_WARNING(Service_AM, "(STUBBED) called");
341
342 std::scoped_lock lk{applet->lock};
343
344 IPC::ResponseBuilder rb{ctx, 3};
345 rb.Push(ResultSuccess);
346 rb.PushRaw<IdleTimeDetectionExtension>(applet->idle_time_detection_extension);
347}
348
349void ISelfController::ReportUserIsActive(HLERequestContext& ctx) {
350 LOG_WARNING(Service_AM, "(STUBBED) called");
351
352 IPC::ResponseBuilder rb{ctx, 2};
353 rb.Push(ResultSuccess);
354}
355
356void ISelfController::SetAutoSleepDisabled(HLERequestContext& ctx) {
357 IPC::RequestParser rp{ctx};
358
359 std::scoped_lock lk{applet->lock};
360 applet->auto_sleep_disabled = rp.Pop<bool>();
361
362 // On the system itself, if the previous state of is_auto_sleep_disabled
363 // differed from the current value passed in, it'd signify the internal
364 // window manager to update (and also increment some statistics like update counts)
365 //
366 // It'd also indicate this change to an idle handling context.
367 //
368 // However, given we're emulating this behavior, most of this can be ignored
369 // and it's sufficient to simply set the member variable for querying via
370 // IsAutoSleepDisabled().
371
372 LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", applet->auto_sleep_disabled);
373
374 IPC::ResponseBuilder rb{ctx, 2};
375 rb.Push(ResultSuccess);
376}
377
378void ISelfController::IsAutoSleepDisabled(HLERequestContext& ctx) {
379 LOG_DEBUG(Service_AM, "called.");
380
381 std::scoped_lock lk{applet->lock};
382
383 IPC::ResponseBuilder rb{ctx, 3};
384 rb.Push(ResultSuccess);
385 rb.Push(applet->auto_sleep_disabled);
386}
387
388void ISelfController::GetAccumulatedSuspendedTickValue(HLERequestContext& ctx) {
389 LOG_DEBUG(Service_AM, "called.");
390
391 std::scoped_lock lk{applet->lock};
392 // This command returns the total number of system ticks since ISelfController creation
393 // where the game was suspended. Since Yuzu doesn't implement game suspension, this command
394 // can just always return 0 ticks.
395 IPC::ResponseBuilder rb{ctx, 4};
396 rb.Push(ResultSuccess);
397 rb.Push<u64>(applet->suspended_ticks);
398}
399
400void ISelfController::GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx) {
401 LOG_DEBUG(Service_AM, "called.");
402
403 IPC::ResponseBuilder rb{ctx, 2, 1};
404 rb.Push(ResultSuccess);
405 rb.PushCopyObjects(applet->accumulated_suspended_tick_changed_event.GetHandle());
406}
407
408void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx) {
409 IPC::RequestParser rp{ctx};
410
411 // This service call sets an internal flag whether a notification is shown when an image is
412 // captured. Currently we do not support capturing images via the capture button, so this can be
413 // stubbed for now.
414 const bool enabled = rp.Pop<bool>();
415 LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
416
417 std::scoped_lock lk{applet->lock};
418 applet->album_image_taken_notification_enabled = enabled;
419
420 IPC::ResponseBuilder rb{ctx, 2};
421 rb.Push(ResultSuccess);
422}
423
424void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) {
425 IPC::RequestParser rp{ctx};
426
427 const auto report_option = rp.PopEnum<Capture::AlbumReportOption>();
428
429 LOG_INFO(Service_AM, "called, report_option={}", report_option);
430
431 const auto screenshot_service =
432 system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
433 "caps:su");
434
435 if (screenshot_service) {
436 screenshot_service->CaptureAndSaveScreenshot(report_option);
437 }
438
439 IPC::ResponseBuilder rb{ctx, 2};
440 rb.Push(ResultSuccess);
441}
442
443void ISelfController::SetRecordVolumeMuted(HLERequestContext& ctx) {
444 IPC::RequestParser rp{ctx};
445
446 const auto enabled = rp.Pop<bool>();
447 LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
448
449 std::scoped_lock lk{applet->lock};
450 applet->record_volume_muted = enabled;
451
452 IPC::ResponseBuilder rb{ctx, 2};
453 rb.Push(ResultSuccess);
454}
455
456} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11struct Applet;
12
13class ISelfController final : public ServiceFramework<ISelfController> {
14public:
15 explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet_,
16 Nvnflinger::Nvnflinger& nvnflinger_);
17 ~ISelfController() override;
18
19private:
20 void Exit(HLERequestContext& ctx);
21 void LockExit(HLERequestContext& ctx);
22 void UnlockExit(HLERequestContext& ctx);
23 void EnterFatalSection(HLERequestContext& ctx);
24 void LeaveFatalSection(HLERequestContext& ctx);
25 void GetLibraryAppletLaunchableEvent(HLERequestContext& ctx);
26 void SetScreenShotPermission(HLERequestContext& ctx);
27 void SetOperationModeChangedNotification(HLERequestContext& ctx);
28 void SetPerformanceModeChangedNotification(HLERequestContext& ctx);
29 void SetFocusHandlingMode(HLERequestContext& ctx);
30 void SetRestartMessageEnabled(HLERequestContext& ctx);
31 void SetScreenShotAppletIdentityInfo(HLERequestContext& ctx);
32 void SetOutOfFocusSuspendingEnabled(HLERequestContext& ctx);
33 void SetAlbumImageOrientation(HLERequestContext& ctx);
34 void IsSystemBufferSharingEnabled(HLERequestContext& ctx);
35 void GetSystemSharedBufferHandle(HLERequestContext& ctx);
36 void GetSystemSharedLayerHandle(HLERequestContext& ctx);
37 void CreateManagedDisplayLayer(HLERequestContext& ctx);
38 void CreateManagedDisplaySeparableLayer(HLERequestContext& ctx);
39 void SetHandlesRequestToDisplay(HLERequestContext& ctx);
40 void ApproveToDisplay(HLERequestContext& ctx);
41 void SetIdleTimeDetectionExtension(HLERequestContext& ctx);
42 void GetIdleTimeDetectionExtension(HLERequestContext& ctx);
43 void ReportUserIsActive(HLERequestContext& ctx);
44 void SetAutoSleepDisabled(HLERequestContext& ctx);
45 void IsAutoSleepDisabled(HLERequestContext& ctx);
46 void GetAccumulatedSuspendedTickValue(HLERequestContext& ctx);
47 void GetAccumulatedSuspendedTickChangedEvent(HLERequestContext& ctx);
48 void SetAlbumImageTakenNotificationEnabled(HLERequestContext& ctx);
49 void SaveCurrentScreenshot(HLERequestContext& ctx);
50 void SetRecordVolumeMuted(HLERequestContext& ctx);
51
52 Result EnsureBufferSharingEnabled(Kernel::KProcess* process);
53
54 Nvnflinger::Nvnflinger& nvnflinger;
55 const std::shared_ptr<Applet> applet;
56};
57
58} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/am_results.h"
5#include "core/hle/service/am/library_applet_storage.h"
6#include "core/hle/service/am/storage.h"
7#include "core/hle/service/am/storage_accessor.h"
8#include "core/hle/service/ipc_helpers.h"
9
10namespace Service::AM {
11
12IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_)
13 : ServiceFramework{system_, "IStorage"}, impl{std::move(impl_)} {
14 static const FunctionInfo functions[] = {
15 {0, &IStorage::Open, "Open"},
16 {1, &IStorage::OpenTransferStorage, "OpenTransferStorage"},
17 };
18
19 RegisterHandlers(functions);
20}
21
22IStorage::IStorage(Core::System& system_, std::vector<u8>&& data)
23 : IStorage(system_, CreateStorage(std::move(data))) {}
24
25IStorage::~IStorage() = default;
26
27void IStorage::Open(HLERequestContext& ctx) {
28 LOG_DEBUG(Service_AM, "called");
29
30 if (impl->GetHandle() != nullptr) {
31 IPC::ResponseBuilder rb{ctx, 2};
32 rb.Push(AM::ResultInvalidStorageType);
33 return;
34 }
35
36 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
37 rb.Push(ResultSuccess);
38 rb.PushIpcInterface<IStorageAccessor>(system, impl);
39}
40
41void IStorage::OpenTransferStorage(HLERequestContext& ctx) {
42 LOG_DEBUG(Service_AM, "called");
43
44 if (impl->GetHandle() == nullptr) {
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(AM::ResultInvalidStorageType);
47 return;
48 }
49
50 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
51 rb.Push(ResultSuccess);
52 rb.PushIpcInterface<ITransferStorageAccessor>(system, impl);
53}
54
55std::vector<u8> IStorage::GetData() const {
56 return impl->GetData();
57}
58
59} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10class LibraryAppletStorage;
11
12class IStorage final : public ServiceFramework<IStorage> {
13public:
14 explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_);
15 explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
16 ~IStorage() override;
17
18 std::shared_ptr<LibraryAppletStorage> GetImpl() const {
19 return impl;
20 }
21
22 std::vector<u8> GetData() const;
23
24private:
25 void Open(HLERequestContext& ctx);
26 void OpenTransferStorage(HLERequestContext& ctx);
27
28 const std::shared_ptr<LibraryAppletStorage> impl;
29};
30
31} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_transfer_memory.h"
5#include "core/hle/service/am/am_results.h"
6#include "core/hle/service/am/library_applet_storage.h"
7#include "core/hle/service/am/storage_accessor.h"
8#include "core/hle/service/ipc_helpers.h"
9
10namespace Service::AM {
11
12IStorageAccessor::IStorageAccessor(Core::System& system_,
13 std::shared_ptr<LibraryAppletStorage> impl_)
14 : ServiceFramework{system_, "IStorageAccessor"}, impl{std::move(impl_)} {
15 static const FunctionInfo functions[] = {
16 {0, &IStorageAccessor::GetSize, "GetSize"},
17 {10, &IStorageAccessor::Write, "Write"},
18 {11, &IStorageAccessor::Read, "Read"},
19 };
20
21 RegisterHandlers(functions);
22}
23
24IStorageAccessor::~IStorageAccessor() = default;
25
26void IStorageAccessor::GetSize(HLERequestContext& ctx) {
27 LOG_DEBUG(Service_AM, "called");
28
29 IPC::ResponseBuilder rb{ctx, 4};
30
31 rb.Push(ResultSuccess);
32 rb.Push(impl->GetSize());
33}
34
35void IStorageAccessor::Write(HLERequestContext& ctx) {
36 IPC::RequestParser rp{ctx};
37
38 const s64 offset{rp.Pop<s64>()};
39 const auto data{ctx.ReadBuffer()};
40 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
41
42 const auto res{impl->Write(offset, data.data(), data.size())};
43
44 IPC::ResponseBuilder rb{ctx, 2};
45 rb.Push(res);
46}
47
48void IStorageAccessor::Read(HLERequestContext& ctx) {
49 IPC::RequestParser rp{ctx};
50
51 const s64 offset{rp.Pop<s64>()};
52 std::vector<u8> data(ctx.GetWriteBufferSize());
53
54 LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
55
56 const auto res{impl->Read(offset, data.data(), data.size())};
57
58 ctx.WriteBuffer(data);
59
60 IPC::ResponseBuilder rb{ctx, 2};
61 rb.Push(res);
62}
63
64ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_,
65 std::shared_ptr<LibraryAppletStorage> impl_)
66 : ServiceFramework{system_, "ITransferStorageAccessor"}, impl{std::move(impl_)} {
67 static const FunctionInfo functions[] = {
68 {0, &ITransferStorageAccessor::GetSize, "GetSize"},
69 {1, &ITransferStorageAccessor::GetHandle, "GetHandle"},
70 };
71
72 RegisterHandlers(functions);
73}
74
75ITransferStorageAccessor::~ITransferStorageAccessor() = default;
76
77void ITransferStorageAccessor::GetSize(HLERequestContext& ctx) {
78 IPC::ResponseBuilder rb{ctx, 4};
79 rb.Push(ResultSuccess);
80 rb.Push(impl->GetSize());
81}
82
83void ITransferStorageAccessor::GetHandle(HLERequestContext& ctx) {
84 IPC::ResponseBuilder rb{ctx, 4, 1};
85 rb.Push(ResultSuccess);
86 rb.Push(impl->GetSize());
87 rb.PushCopyObjects(impl->GetHandle());
88}
89
90} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/am/storage.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
12public:
13 explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl_);
14 ~IStorageAccessor() override;
15
16private:
17 void GetSize(HLERequestContext& ctx);
18 void Write(HLERequestContext& ctx);
19 void Read(HLERequestContext& ctx);
20
21 const std::shared_ptr<LibraryAppletStorage> impl;
22};
23
24class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> {
25public:
26 explicit ITransferStorageAccessor(Core::System& system_,
27 std::shared_ptr<LibraryAppletStorage> impl_);
28 ~ITransferStorageAccessor() override;
29
30private:
31 void GetSize(HLERequestContext& ctx);
32 void GetHandle(HLERequestContext& ctx);
33
34 const std::shared_ptr<LibraryAppletStorage> impl;
35};
36
37} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet_common_functions.h"
5#include "core/hle/service/am/application_creator.h"
6#include "core/hle/service/am/audio_controller.h"
7#include "core/hle/service/am/common_state_getter.h"
8#include "core/hle/service/am/debug_functions.h"
9#include "core/hle/service/am/display_controller.h"
10#include "core/hle/service/am/global_state_controller.h"
11#include "core/hle/service/am/home_menu_functions.h"
12#include "core/hle/service/am/library_applet_creator.h"
13#include "core/hle/service/am/library_applet_self_accessor.h"
14#include "core/hle/service/am/process_winding_controller.h"
15#include "core/hle/service/am/self_controller.h"
16#include "core/hle/service/am/system_applet_proxy.h"
17#include "core/hle/service/am/window_controller.h"
18#include "core/hle/service/ipc_helpers.h"
19
20namespace Service::AM {
21
22ISystemAppletProxy::ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
23 std::shared_ptr<Applet> applet_, Core::System& system_)
24 : ServiceFramework{system_, "ISystemAppletProxy"}, nvnflinger{nvnflinger_}, applet{std::move(
25 applet_)} {
26 // clang-format off
27 static const FunctionInfo functions[] = {
28 {0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
29 {1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
30 {2, &ISystemAppletProxy::GetWindowController, "GetWindowController"},
31 {3, &ISystemAppletProxy::GetAudioController, "GetAudioController"},
32 {4, &ISystemAppletProxy::GetDisplayController, "GetDisplayController"},
33 {10, nullptr, "GetProcessWindingController"},
34 {11, &ISystemAppletProxy::GetLibraryAppletCreator, "GetLibraryAppletCreator"},
35 {20, &ISystemAppletProxy::GetHomeMenuFunctions, "GetHomeMenuFunctions"},
36 {21, &ISystemAppletProxy::GetGlobalStateController, "GetGlobalStateController"},
37 {22, &ISystemAppletProxy::GetApplicationCreator, "GetApplicationCreator"},
38 {23, &ISystemAppletProxy::GetAppletCommonFunctions, "GetAppletCommonFunctions"},
39 {1000, &ISystemAppletProxy::GetDebugFunctions, "GetDebugFunctions"},
40 };
41 // clang-format on
42
43 RegisterHandlers(functions);
44}
45
46ISystemAppletProxy::~ISystemAppletProxy() = default;
47
48void ISystemAppletProxy::GetCommonStateGetter(HLERequestContext& ctx) {
49 LOG_DEBUG(Service_AM, "called");
50
51 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
52 rb.Push(ResultSuccess);
53 rb.PushIpcInterface<ICommonStateGetter>(system, applet);
54}
55
56void ISystemAppletProxy::GetSelfController(HLERequestContext& ctx) {
57 LOG_DEBUG(Service_AM, "called");
58
59 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
60 rb.Push(ResultSuccess);
61 rb.PushIpcInterface<ISelfController>(system, applet, nvnflinger);
62}
63
64void ISystemAppletProxy::GetWindowController(HLERequestContext& ctx) {
65 LOG_DEBUG(Service_AM, "called");
66
67 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
68 rb.Push(ResultSuccess);
69 rb.PushIpcInterface<IWindowController>(system, applet);
70}
71
72void ISystemAppletProxy::GetAudioController(HLERequestContext& ctx) {
73 LOG_DEBUG(Service_AM, "called");
74
75 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
76 rb.Push(ResultSuccess);
77 rb.PushIpcInterface<IAudioController>(system);
78}
79
80void ISystemAppletProxy::GetDisplayController(HLERequestContext& ctx) {
81 LOG_DEBUG(Service_AM, "called");
82
83 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
84 rb.Push(ResultSuccess);
85 rb.PushIpcInterface<IDisplayController>(system, applet);
86}
87
88void ISystemAppletProxy::GetLibraryAppletCreator(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_AM, "called");
90
91 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
92 rb.Push(ResultSuccess);
93 rb.PushIpcInterface<ILibraryAppletCreator>(system, applet);
94}
95
96void ISystemAppletProxy::GetHomeMenuFunctions(HLERequestContext& ctx) {
97 LOG_DEBUG(Service_AM, "called");
98
99 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
100 rb.Push(ResultSuccess);
101 rb.PushIpcInterface<IHomeMenuFunctions>(system);
102}
103
104void ISystemAppletProxy::GetGlobalStateController(HLERequestContext& ctx) {
105 LOG_DEBUG(Service_AM, "called");
106
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(ResultSuccess);
109 rb.PushIpcInterface<IGlobalStateController>(system);
110}
111
112void ISystemAppletProxy::GetApplicationCreator(HLERequestContext& ctx) {
113 LOG_DEBUG(Service_AM, "called");
114
115 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
116 rb.Push(ResultSuccess);
117 rb.PushIpcInterface<IApplicationCreator>(system);
118}
119
120void ISystemAppletProxy::GetAppletCommonFunctions(HLERequestContext& ctx) {
121 LOG_DEBUG(Service_AM, "called");
122
123 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
124 rb.Push(ResultSuccess);
125 rb.PushIpcInterface<IAppletCommonFunctions>(system, applet);
126}
127
128void ISystemAppletProxy::GetDebugFunctions(HLERequestContext& ctx) {
129 LOG_DEBUG(Service_AM, "called");
130
131 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
132 rb.Push(ResultSuccess);
133 rb.PushIpcInterface<IDebugFunctions>(system);
134}
135
136} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/am/applet_message_queue.h"
7#include "core/hle/service/service.h"
8
9namespace Service::AM {
10
11struct Applet;
12
13class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
14public:
15 explicit ISystemAppletProxy(Nvnflinger::Nvnflinger& nvnflinger_,
16 std::shared_ptr<Applet> applet_, Core::System& system_);
17 ~ISystemAppletProxy();
18
19private:
20 void GetCommonStateGetter(HLERequestContext& ctx);
21 void GetSelfController(HLERequestContext& ctx);
22 void GetWindowController(HLERequestContext& ctx);
23 void GetAudioController(HLERequestContext& ctx);
24 void GetDisplayController(HLERequestContext& ctx);
25 void GetLibraryAppletCreator(HLERequestContext& ctx);
26 void GetHomeMenuFunctions(HLERequestContext& ctx);
27 void GetGlobalStateController(HLERequestContext& ctx);
28 void GetApplicationCreator(HLERequestContext& ctx);
29 void GetAppletCommonFunctions(HLERequestContext& ctx);
30 void GetDebugFunctions(HLERequestContext& ctx);
31
32 Nvnflinger::Nvnflinger& nvnflinger;
33 std::shared_ptr<Applet> applet;
34};
35
36} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/system_buffer_manager.h"
5#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
6#include "core/hle/service/nvnflinger/nvnflinger.h"
7#include "core/hle/service/vi/vi_results.h"
8
9namespace Service::AM {
10
11SystemBufferManager::SystemBufferManager() = default;
12
13SystemBufferManager::~SystemBufferManager() {
14 if (!m_nvnflinger) {
15 return;
16 }
17
18 // Clean up shared layers.
19 if (m_buffer_sharing_enabled) {
20 }
21}
22
23bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process,
24 AppletId applet_id) {
25 if (m_nvnflinger) {
26 return m_buffer_sharing_enabled;
27 }
28
29 m_process = process;
30 m_nvnflinger = nvnflinger;
31 m_buffer_sharing_enabled = false;
32 m_system_shared_buffer_id = 0;
33 m_system_shared_layer_id = 0;
34
35 if (applet_id <= AppletId::Application) {
36 return false;
37 }
38
39 const auto display_id = m_nvnflinger->OpenDisplay("Default").value();
40 const auto res = m_nvnflinger->GetSystemBufferManager().Initialize(
41 &m_system_shared_buffer_id, &m_system_shared_layer_id, display_id);
42
43 if (res.IsSuccess()) {
44 m_buffer_sharing_enabled = true;
45 m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
46 }
47
48 return m_buffer_sharing_enabled;
49}
50
51void SystemBufferManager::SetWindowVisibility(bool visible) {
52 if (m_visible == visible) {
53 return;
54 }
55
56 m_visible = visible;
57
58 if (m_nvnflinger) {
59 m_nvnflinger->SetLayerVisibility(m_system_shared_layer_id, m_visible);
60 }
61}
62
63Result SystemBufferManager::WriteAppletCaptureBuffer(bool* out_was_written,
64 s32* out_fbshare_layer_index) {
65 // TODO
66 R_SUCCEED();
67}
68
69} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <set>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10
11#include "core/hle/service/am/am_types.h"
12
13namespace Kernel {
14class KProcess;
15}
16
17namespace Service::Nvnflinger {
18class Nvnflinger;
19}
20
21union Result;
22
23namespace Service::AM {
24
25class SystemBufferManager {
26public:
27 SystemBufferManager();
28 ~SystemBufferManager();
29
30 bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id);
31
32 void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id,
33 u64* out_system_shared_layer_id) {
34 *out_system_shared_buffer_id = m_system_shared_buffer_id;
35 *out_system_shared_layer_id = m_system_shared_layer_id;
36 }
37
38 void SetWindowVisibility(bool visible);
39
40 Result WriteAppletCaptureBuffer(bool* out_was_written, s32* out_fbshare_layer_index);
41
42private:
43 Kernel::KProcess* m_process{};
44 Nvnflinger::Nvnflinger* m_nvnflinger{};
45 bool m_buffer_sharing_enabled{};
46 bool m_visible{true};
47 u64 m_system_shared_buffer_id{};
48 u64 m_system_shared_layer_id{};
49};
50
51} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/service/am/applet.h"
5#include "core/hle/service/am/window_controller.h"
6#include "core/hle/service/ipc_helpers.h"
7
8namespace Service::AM {
9
10IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_)
11 : ServiceFramework{system_, "IWindowController"}, applet{std::move(applet_)} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, nullptr, "CreateWindow"},
15 {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
16 {2, &IWindowController::GetAppletResourceUserIdOfCallerApplet, "GetAppletResourceUserIdOfCallerApplet"},
17 {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
18 {11, nullptr, "ReleaseForegroundRights"},
19 {12, nullptr, "RejectToChangeIntoBackground"},
20 {20, &IWindowController::SetAppletWindowVisibility, "SetAppletWindowVisibility"},
21 {21, &IWindowController::SetAppletGpuTimeSlice, "SetAppletGpuTimeSlice"},
22 };
23 // clang-format on
24
25 RegisterHandlers(functions);
26}
27
28IWindowController::~IWindowController() = default;
29
30void IWindowController::GetAppletResourceUserId(HLERequestContext& ctx) {
31 IPC::ResponseBuilder rb{ctx, 4};
32 rb.Push(ResultSuccess);
33 rb.Push<u64>(applet->aruid);
34}
35
36void IWindowController::GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx) {
37 u64 aruid = 0;
38 if (auto caller = applet->caller_applet.lock(); caller) {
39 aruid = caller->aruid;
40 }
41
42 LOG_WARNING(Service_AM, "(STUBBED) called");
43
44 IPC::ResponseBuilder rb{ctx, 4};
45 rb.Push(ResultSuccess);
46 rb.Push<u64>(aruid);
47}
48
49void IWindowController::AcquireForegroundRights(HLERequestContext& ctx) {
50 LOG_WARNING(Service_AM, "(STUBBED) called");
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(ResultSuccess);
53}
54
55void IWindowController::SetAppletWindowVisibility(HLERequestContext& ctx) {
56 LOG_INFO(Service_AM, "called");
57
58 IPC::RequestParser rp{ctx};
59 const bool visible = rp.Pop<bool>();
60
61 applet->system_buffer_manager.SetWindowVisibility(visible);
62 applet->hid_registration.EnableAppletToGetInput(visible);
63
64 if (visible) {
65 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
66 applet->focus_state = FocusState::InFocus;
67 } else {
68 applet->focus_state = FocusState::NotInFocus;
69 }
70 applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
71
72 IPC::ResponseBuilder rb{ctx, 2};
73 rb.Push(ResultSuccess);
74}
75
76void IWindowController::SetAppletGpuTimeSlice(HLERequestContext& ctx) {
77 IPC::RequestParser rp{ctx};
78 const auto time_slice = rp.Pop<s64>();
79
80 LOG_WARNING(Service_AM, "(STUBBED) called, time_slice={}", time_slice);
81
82 IPC::ResponseBuilder rb{ctx, 2};
83 rb.Push(ResultSuccess);
84}
85
86} // 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 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/service/service.h"
7
8namespace Service::AM {
9
10struct Applet;
11
12class IWindowController final : public ServiceFramework<IWindowController> {
13public:
14 explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet_);
15 ~IWindowController() override;
16
17private:
18 void GetAppletResourceUserId(HLERequestContext& ctx);
19 void GetAppletResourceUserIdOfCallerApplet(HLERequestContext& ctx);
20 void AcquireForegroundRights(HLERequestContext& ctx);
21 void SetAppletWindowVisibility(HLERequestContext& ctx);
22 void SetAppletGpuTimeSlice(HLERequestContext& ctx);
23
24 const std::shared_ptr<Applet> applet;
25};
26
27} // 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) {
202 LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count, 202 LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
203 process_id); 203 process_id);
204 204
205 const auto current = system.GetApplicationProcessProgramID(); 205 const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
206 206
207 std::vector<u32> out; 207 std::vector<u32> out;
208 const auto& disabled = Settings::values.disabled_addons[current]; 208 const auto& disabled = Settings::values.disabled_addons[current];
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp
index e3b8ecf3e..3a22b135f 100644
--- a/src/core/hle/service/caps/caps_manager.cpp
+++ b/src/core/hle/service/caps/caps_manager.cpp
@@ -246,10 +246,10 @@ Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
246 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); 246 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
247 247
248 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{}; 248 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{};
249 static_service->GetStandardUserSystemClock(user_clock); 249 static_service->GetStandardUserSystemClock(&user_clock);
250 250
251 s64 posix_time{}; 251 s64 posix_time{};
252 auto result = user_clock->GetCurrentTime(posix_time); 252 auto result = user_clock->GetCurrentTime(&posix_time);
253 253
254 if (result.IsError()) { 254 if (result.IsError()) {
255 return result; 255 return result;
@@ -268,10 +268,10 @@ Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
268 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); 268 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
269 269
270 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{}; 270 std::shared_ptr<Service::PSC::Time::SystemClock> user_clock{};
271 static_service->GetStandardUserSystemClock(user_clock); 271 static_service->GetStandardUserSystemClock(&user_clock);
272 272
273 s64 posix_time{}; 273 s64 posix_time{};
274 auto result = user_clock->GetCurrentTime(posix_time); 274 auto result = user_clock->GetCurrentTime(&posix_time);
275 275
276 if (result.IsError()) { 276 if (result.IsError()) {
277 return result; 277 return result;
@@ -470,11 +470,11 @@ AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
470 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); 470 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
471 471
472 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{}; 472 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{};
473 static_service->GetTimeZoneService(timezone_service); 473 static_service->GetTimeZoneService(&timezone_service);
474 474
475 Service::PSC::Time::CalendarTime calendar_time{}; 475 Service::PSC::Time::CalendarTime calendar_time{};
476 Service::PSC::Time::CalendarAdditionalInfo additional_info{}; 476 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
477 timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time); 477 timezone_service->ToCalendarTimeWithMyRule(&calendar_time, &additional_info, posix_time);
478 478
479 return { 479 return {
480 .year = calendar_time.year, 480 .year = calendar_time.year,
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
index 9eb10e816..315475e71 100644
--- a/src/core/hle/service/cmif_serialization.h
+++ b/src/core/hle/service/cmif_serialization.h
@@ -12,6 +12,109 @@
12namespace Service { 12namespace Service {
13 13
14// clang-format off 14// clang-format off
15template <typename T>
16struct UnwrapArg {
17 using Type = std::remove_cvref_t<T>;
18};
19
20template <typename T, int A>
21struct UnwrapArg<InLargeData<T, A>> {
22 using Type = std::remove_cv_t<typename InLargeData<T, A>::Type>;
23};
24
25template <typename T>
26struct UnwrapArg<Out<T>> {
27 using Type = AutoOut<typename Out<T>::Type>;
28};
29
30template <typename T>
31struct UnwrapArg<OutCopyHandle<T>> {
32 using Type = AutoOut<typename OutCopyHandle<T>::Type>;
33};
34
35template <typename T>
36struct UnwrapArg<OutMoveHandle<T>> {
37 using Type = AutoOut<typename OutMoveHandle<T>::Type>;
38};
39
40template <typename T, int A>
41struct UnwrapArg<OutLargeData<T, A>> {
42 using Type = AutoOut<typename OutLargeData<T, A>::Type>;
43};
44
45enum class ArgumentType {
46 InProcessId,
47 InData,
48 InInterface,
49 InCopyHandle,
50 OutData,
51 OutInterface,
52 OutCopyHandle,
53 OutMoveHandle,
54 InBuffer,
55 InLargeData,
56 OutBuffer,
57 OutLargeData,
58};
59
60template <typename T>
61struct ArgumentTraits;
62
63template <>
64struct ArgumentTraits<ClientProcessId> {
65 static constexpr ArgumentType Type = ArgumentType::InProcessId;
66};
67
68template <typename T>
69struct ArgumentTraits<SharedPointer<T>> {
70 static constexpr ArgumentType Type = ArgumentType::InInterface;
71};
72
73template <typename T>
74struct ArgumentTraits<InCopyHandle<T>> {
75 static constexpr ArgumentType Type = ArgumentType::InCopyHandle;
76};
77
78template <typename T>
79struct ArgumentTraits<Out<SharedPointer<T>>> {
80 static constexpr ArgumentType Type = ArgumentType::OutInterface;
81};
82
83template <typename T>
84struct ArgumentTraits<Out<T>> {
85 static constexpr ArgumentType Type = ArgumentType::OutData;
86};
87
88template <typename T>
89struct ArgumentTraits<OutCopyHandle<T>> {
90 static constexpr ArgumentType Type = ArgumentType::OutCopyHandle;
91};
92
93template <typename T>
94struct ArgumentTraits<OutMoveHandle<T>> {
95 static constexpr ArgumentType Type = ArgumentType::OutMoveHandle;
96};
97
98template <typename T, int A>
99struct ArgumentTraits<Buffer<T, A>> {
100 static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutBuffer : ArgumentType::InBuffer;
101};
102
103template <typename T, int A>
104struct ArgumentTraits<InLargeData<T, A>> {
105 static constexpr ArgumentType Type = ArgumentType::InLargeData;
106};
107
108template <typename T, int A>
109struct ArgumentTraits<OutLargeData<T, A>> {
110 static constexpr ArgumentType Type = ArgumentType::OutLargeData;
111};
112
113template <typename T>
114struct ArgumentTraits {
115 static constexpr ArgumentType Type = ArgumentType::InData;
116};
117
15struct RequestLayout { 118struct RequestLayout {
16 u32 copy_handle_count; 119 u32 copy_handle_count;
17 u32 move_handle_count; 120 u32 move_handle_count;
@@ -19,14 +122,14 @@ struct RequestLayout {
19 u32 domain_interface_count; 122 u32 domain_interface_count;
20}; 123};
21 124
22template <ArgumentType Type1, ArgumentType Type2, typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0> 125template <typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0>
23constexpr u32 GetArgumentRawDataSize() { 126constexpr u32 GetInRawDataSize() {
24 if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) { 127 if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) {
25 return static_cast<u32>(DataOffset); 128 return static_cast<u32>(DataOffset);
26 } else { 129 } else {
27 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; 130 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
28 131
29 if constexpr (ArgumentTraits<ArgType>::Type == Type1 || ArgumentTraits<ArgType>::Type == Type2) { 132 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InData || ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) {
30 constexpr size_t ArgAlign = alignof(ArgType); 133 constexpr size_t ArgAlign = alignof(ArgType);
31 constexpr size_t ArgSize = sizeof(ArgType); 134 constexpr size_t ArgSize = sizeof(ArgType);
32 135
@@ -35,9 +138,33 @@ constexpr u32 GetArgumentRawDataSize() {
35 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); 138 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
36 constexpr size_t ArgEnd = ArgOffset + ArgSize; 139 constexpr size_t ArgEnd = ArgOffset + ArgSize;
37 140
38 return GetArgumentRawDataSize<Type1, Type2, MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>(); 141 return GetInRawDataSize<MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>();
39 } else { 142 } else {
40 return GetArgumentRawDataSize<Type1, Type2, MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>(); 143 return GetInRawDataSize<MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>();
144 }
145 }
146}
147
148template <typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0>
149constexpr u32 GetOutRawDataSize() {
150 if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) {
151 return static_cast<u32>(DataOffset);
152 } else {
153 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
154
155 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) {
156 using RawArgType = typename ArgType::Type;
157 constexpr size_t ArgAlign = alignof(RawArgType);
158 constexpr size_t ArgSize = sizeof(RawArgType);
159
160 static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment");
161
162 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
163 constexpr size_t ArgEnd = ArgOffset + ArgSize;
164
165 return GetOutRawDataSize<MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>();
166 } else {
167 return GetOutRawDataSize<MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>();
41 } 168 }
42 } 169 }
43} 170}
@@ -62,7 +189,7 @@ constexpr RequestLayout GetNonDomainReplyInLayout() {
62 return RequestLayout{ 189 return RequestLayout{
63 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), 190 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(),
64 .move_handle_count = 0, 191 .move_handle_count = 0,
65 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), 192 .cmif_raw_data_size = GetInRawDataSize<MethodArguments>(),
66 .domain_interface_count = 0, 193 .domain_interface_count = 0,
67 }; 194 };
68} 195}
@@ -72,7 +199,7 @@ constexpr RequestLayout GetDomainReplyInLayout() {
72 return RequestLayout{ 199 return RequestLayout{
73 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), 200 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(),
74 .move_handle_count = 0, 201 .move_handle_count = 0,
75 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), 202 .cmif_raw_data_size = GetInRawDataSize<MethodArguments>(),
76 .domain_interface_count = GetArgumentTypeCount<ArgumentType::InInterface, MethodArguments>(), 203 .domain_interface_count = GetArgumentTypeCount<ArgumentType::InInterface, MethodArguments>(),
77 }; 204 };
78} 205}
@@ -82,7 +209,7 @@ constexpr RequestLayout GetNonDomainReplyOutLayout() {
82 return RequestLayout{ 209 return RequestLayout{
83 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), 210 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(),
84 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>() + GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), 211 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>() + GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(),
85 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), 212 .cmif_raw_data_size = GetOutRawDataSize<MethodArguments>(),
86 .domain_interface_count = 0, 213 .domain_interface_count = 0,
87 }; 214 };
88} 215}
@@ -92,7 +219,7 @@ constexpr RequestLayout GetDomainReplyOutLayout() {
92 return RequestLayout{ 219 return RequestLayout{
93 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), 220 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(),
94 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>(), 221 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>(),
95 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), 222 .cmif_raw_data_size = GetOutRawDataSize<MethodArguments>(),
96 .domain_interface_count = GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), 223 .domain_interface_count = GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(),
97 }; 224 };
98} 225}
@@ -122,6 +249,8 @@ void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLE
122 249
123 static_assert(PrevAlign <= ArgAlign, "Input argument is not ordered by alignment"); 250 static_assert(PrevAlign <= ArgAlign, "Input argument is not ordered by alignment");
124 static_assert(!RawDataFinished, "All input interface arguments must appear after raw data"); 251 static_assert(!RawDataFinished, "All input interface arguments must appear after raw data");
252 static_assert(!std::is_pointer_v<ArgType>, "Input raw data must not be a pointer");
253 static_assert(std::is_trivially_copyable_v<ArgType>, "Input raw data must be trivially copyable");
125 254
126 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); 255 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
127 constexpr size_t ArgEnd = ArgOffset + ArgSize; 256 constexpr size_t ArgEnd = ArgOffset + ArgSize;
@@ -154,7 +283,7 @@ void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLE
154 283
155 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 284 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
156 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { 285 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) {
157 constexpr size_t BufferSize = sizeof(ArgType); 286 constexpr size_t BufferSize = sizeof(typename ArgType::Type);
158 287
159 // Clear the existing data. 288 // Clear the existing data.
160 std::memset(&std::get<ArgIndex>(args), 0, BufferSize); 289 std::memset(&std::get<ArgIndex>(args), 0, BufferSize);
@@ -195,10 +324,10 @@ void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLE
195 324
196 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 325 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
197 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { 326 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) {
198 constexpr size_t BufferSize = sizeof(ArgType); 327 constexpr size_t BufferSize = sizeof(typename ArgType::Type);
199 328
200 // Clear the existing data. 329 // Clear the existing data.
201 std::memset(&std::get<ArgIndex>(args), 0, BufferSize); 330 std::memset(&std::get<ArgIndex>(args).raw, 0, BufferSize);
202 331
203 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 332 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
204 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { 333 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) {
@@ -232,36 +361,40 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
232 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; 361 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
233 362
234 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) { 363 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) {
235 constexpr size_t ArgAlign = alignof(ArgType); 364 using RawArgType = decltype(std::get<ArgIndex>(args).raw);
236 constexpr size_t ArgSize = sizeof(ArgType); 365 constexpr size_t ArgAlign = alignof(RawArgType);
366 constexpr size_t ArgSize = sizeof(RawArgType);
237 367
238 static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment"); 368 static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment");
239 static_assert(!RawDataFinished, "All output interface arguments must appear after raw data"); 369 static_assert(!RawDataFinished, "All output interface arguments must appear after raw data");
370 static_assert(!std::is_pointer_v<ArgType>, "Output raw data must not be a pointer");
371 static_assert(!std::is_pointer_v<RawArgType>, "Output raw data must not be a pointer");
372 static_assert(std::is_trivially_copyable_v<RawArgType>, "Output raw data must be trivially copyable");
240 373
241 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); 374 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
242 constexpr size_t ArgEnd = ArgOffset + ArgSize; 375 constexpr size_t ArgEnd = ArgOffset + ArgSize;
243 376
244 std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize); 377 std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args).raw, ArgSize);
245 378
246 return WriteOutArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 379 return WriteOutArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
247 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) { 380 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) {
248 if (is_domain) { 381 if (is_domain) {
249 ctx.AddDomainObject(std::get<ArgIndex>(args)); 382 ctx.AddDomainObject(std::get<ArgIndex>(args).raw);
250 } else { 383 } else {
251 ctx.AddMoveInterface(std::get<ArgIndex>(args)); 384 ctx.AddMoveInterface(std::get<ArgIndex>(args).raw);
252 } 385 }
253 386
254 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 387 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
255 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) { 388 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) {
256 ctx.AddCopyObject(std::get<ArgIndex>(args)); 389 ctx.AddCopyObject(std::get<ArgIndex>(args).raw);
257 390
258 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 391 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
259 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) { 392 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) {
260 ctx.AddMoveObject(std::get<ArgIndex>(args)); 393 ctx.AddMoveObject(std::get<ArgIndex>(args).raw);
261 394
262 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 395 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
263 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { 396 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) {
264 constexpr size_t BufferSize = sizeof(ArgType); 397 constexpr size_t BufferSize = sizeof(typename ArgType::Type);
265 398
266 ASSERT(ctx.CanWriteBuffer(OutBufferIndex)); 399 ASSERT(ctx.CanWriteBuffer(OutBufferIndex));
267 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { 400 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
@@ -302,10 +435,10 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
302 } 435 }
303 const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false; 436 const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false;
304 437
305 using MethodArguments = std::tuple<std::remove_reference_t<A>...>; 438 using MethodArguments = std::tuple<std::remove_cvref_t<A>...>;
306 439
307 OutTemporaryBuffers buffers{}; 440 OutTemporaryBuffers buffers{};
308 auto call_arguments = std::tuple<typename RemoveOut<A>::Type...>(); 441 auto call_arguments = std::tuple<typename UnwrapArg<A>::Type...>();
309 442
310 // Read inputs. 443 // Read inputs.
311 const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2; 444 const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2;
diff --git a/src/core/hle/service/cmif_types.h b/src/core/hle/service/cmif_types.h
index 2610c49f3..dc06169f4 100644
--- a/src/core/hle/service/cmif_types.h
+++ b/src/core/hle/service/cmif_types.h
@@ -13,21 +13,30 @@ namespace Service {
13 13
14// clang-format off 14// clang-format off
15template <typename T> 15template <typename T>
16struct AutoOut {
17 T raw;
18};
19
20template <typename T>
16class Out { 21class Out {
17public: 22public:
18 using Type = T; 23 using Type = T;
19 24
20 /* implicit */ Out(Type& t) : raw(&t) {} 25 /* implicit */ Out(AutoOut<Type>& t) : raw(&t.raw) {}
21 ~Out() = default; 26 /* implicit */ Out(Type* t) : raw(t) {}
22 27
23 Type* Get() const { 28 Type* Get() const {
24 return raw; 29 return raw;
25 } 30 }
26 31
27 Type& operator*() { 32 Type& operator*() const {
28 return *raw; 33 return *raw;
29 } 34 }
30 35
36 Type* operator->() const {
37 return raw;
38 }
39
31private: 40private:
32 Type* raw; 41 Type* raw;
33}; 42};
@@ -35,6 +44,9 @@ private:
35template <typename T> 44template <typename T>
36using SharedPointer = std::shared_ptr<T>; 45using SharedPointer = std::shared_ptr<T>;
37 46
47template <typename T>
48using OutInterface = Out<SharedPointer<T>>;
49
38struct ClientProcessId { 50struct ClientProcessId {
39 explicit operator bool() const { 51 explicit operator bool() const {
40 return pid != 0; 52 return pid != 0;
@@ -101,17 +113,21 @@ class OutCopyHandle {
101public: 113public:
102 using Type = T*; 114 using Type = T*;
103 115
104 /* implicit */ OutCopyHandle(Type& t) : raw(&t) {} 116 /* implicit */ OutCopyHandle(AutoOut<Type>& t) : raw(&t.raw) {}
105 ~OutCopyHandle() = default; 117 /* implicit */ OutCopyHandle(Type* t) : raw(t) {}
106 118
107 Type* Get() const { 119 Type* Get() const {
108 return raw; 120 return raw;
109 } 121 }
110 122
111 Type& operator*() { 123 Type& operator*() const {
112 return *raw; 124 return *raw;
113 } 125 }
114 126
127 Type* operator->() const {
128 return raw;
129 }
130
115private: 131private:
116 Type* raw; 132 Type* raw;
117}; 133};
@@ -121,30 +137,34 @@ class OutMoveHandle {
121public: 137public:
122 using Type = T*; 138 using Type = T*;
123 139
124 /* implicit */ OutMoveHandle(Type& t) : raw(&t) {} 140 /* implicit */ OutMoveHandle(AutoOut<Type>& t) : raw(&t.raw) {}
125 ~OutMoveHandle() = default; 141 /* implicit */ OutMoveHandle(Type* t) : raw(t) {}
126 142
127 Type* Get() const { 143 Type* Get() const {
128 return raw; 144 return raw;
129 } 145 }
130 146
131 Type& operator*() { 147 Type& operator*() const {
132 return *raw; 148 return *raw;
133 } 149 }
134 150
151 Type* operator->() const {
152 return raw;
153 }
154
135private: 155private:
136 Type* raw; 156 Type* raw;
137}; 157};
138 158
139enum BufferAttr : int { 159enum BufferAttr : int {
140 BufferAttr_In = (1U << 0), 160 /* 0x01 */ BufferAttr_In = (1U << 0),
141 BufferAttr_Out = (1U << 1), 161 /* 0x02 */ BufferAttr_Out = (1U << 1),
142 BufferAttr_HipcMapAlias = (1U << 2), 162 /* 0x04 */ BufferAttr_HipcMapAlias = (1U << 2),
143 BufferAttr_HipcPointer = (1U << 3), 163 /* 0x08 */ BufferAttr_HipcPointer = (1U << 3),
144 BufferAttr_FixedSize = (1U << 4), 164 /* 0x10 */ BufferAttr_FixedSize = (1U << 4),
145 BufferAttr_HipcAutoSelect = (1U << 5), 165 /* 0x20 */ BufferAttr_HipcAutoSelect = (1U << 5),
146 BufferAttr_HipcMapTransferAllowsNonSecure = (1U << 6), 166 /* 0x40 */ BufferAttr_HipcMapTransferAllowsNonSecure = (1U << 6),
147 BufferAttr_HipcMapTransferAllowsNonDevice = (1U << 7), 167 /* 0x80 */ BufferAttr_HipcMapTransferAllowsNonDevice = (1U << 7),
148}; 168};
149 169
150template <typename T, int A> 170template <typename T, int A>
@@ -172,123 +192,80 @@ struct Buffer : public std::span<T> {
172 } 192 }
173}; 193};
174 194
175template <BufferAttr A> 195template <int A>
176using InBuffer = Buffer<const u8, BufferAttr_In | A>; 196using InBuffer = Buffer<const u8, BufferAttr_In | A>;
177 197
178template <typename T, BufferAttr A> 198template <typename T, int A>
179using InArray = Buffer<T, BufferAttr_In | A>; 199using InArray = Buffer<T, BufferAttr_In | A>;
180 200
181template <BufferAttr A> 201template <int A>
182using OutBuffer = Buffer<u8, BufferAttr_Out | A>; 202using OutBuffer = Buffer<u8, BufferAttr_Out | A>;
183 203
184template <typename T, BufferAttr A> 204template <typename T, int A>
185using OutArray = Buffer<T, BufferAttr_Out | A>; 205using OutArray = Buffer<T, BufferAttr_Out | A>;
186 206
187template <typename T, int A> 207template <typename T, int A>
188struct LargeData : public T { 208class InLargeData {
209public:
189 static_assert(std::is_trivially_copyable_v<T>, "LargeData type must be trivially copyable"); 210 static_assert(std::is_trivially_copyable_v<T>, "LargeData type must be trivially copyable");
190 static_assert((A & BufferAttr_FixedSize) != 0, "LargeData attr must contain FixedSize"); 211 static_assert((A & BufferAttr_Out) == 0, "InLargeData attr must not be Out");
191 static_assert(((A & BufferAttr_In) == 0) ^ ((A & BufferAttr_Out) == 0), "LargeData attr must be In or Out"); 212 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize);
192 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A); 213 using Type = const T;
193 using Type = T;
194
195 /* implicit */ LargeData(const T& rhs) : T(rhs) {}
196 /* implicit */ LargeData() = default;
197};
198
199template <typename T, BufferAttr A>
200using InLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_In | A>;
201
202template <typename T, BufferAttr A>
203using OutLargeData = LargeData<T, BufferAttr_FixedSize | BufferAttr_Out | A>;
204 214
205template <typename T> 215 /* implicit */ InLargeData(Type& t) : raw(&t) {}
206struct RemoveOut { 216 ~InLargeData() = default;
207 using Type = std::remove_reference_t<T>;
208};
209
210template <typename T>
211struct RemoveOut<Out<T>> {
212 using Type = typename Out<T>::Type;
213};
214 217
215template <typename T> 218 InLargeData& operator=(Type* rhs) {
216struct RemoveOut<OutCopyHandle<T>> { 219 raw = rhs;
217 using Type = typename OutCopyHandle<T>::Type; 220 return *this;
218}; 221 }
219
220template <typename T>
221struct RemoveOut<OutMoveHandle<T>> {
222 using Type = typename OutMoveHandle<T>::Type;
223};
224
225enum class ArgumentType {
226 InProcessId,
227 InData,
228 InInterface,
229 InCopyHandle,
230 OutData,
231 OutInterface,
232 OutCopyHandle,
233 OutMoveHandle,
234 InBuffer,
235 InLargeData,
236 OutBuffer,
237 OutLargeData,
238};
239 222
240template <typename T> 223 Type* Get() const {
241struct ArgumentTraits; 224 return raw;
225 }
242 226
243template <> 227 Type& operator*() const {
244struct ArgumentTraits<ClientProcessId> { 228 return *raw;
245 static constexpr ArgumentType Type = ArgumentType::InProcessId; 229 }
246};
247 230
248template <typename T> 231 Type* operator->() const {
249struct ArgumentTraits<SharedPointer<T>> { 232 return raw;
250 static constexpr ArgumentType Type = ArgumentType::InInterface; 233 }
251};
252 234
253template <typename T> 235 explicit operator bool() const {
254struct ArgumentTraits<InCopyHandle<T>> { 236 return raw != nullptr;
255 static constexpr ArgumentType Type = ArgumentType::InCopyHandle; 237 }
256};
257 238
258template <typename T> 239private:
259struct ArgumentTraits<Out<SharedPointer<T>>> { 240 Type* raw;
260 static constexpr ArgumentType Type = ArgumentType::OutInterface;
261}; 241};
262 242
263template <typename T> 243template <typename T, int A>
264struct ArgumentTraits<Out<T>> { 244class OutLargeData {
265 static constexpr ArgumentType Type = ArgumentType::OutData; 245public:
266}; 246 static_assert(std::is_trivially_copyable_v<T>, "LargeData type must be trivially copyable");
247 static_assert((A & BufferAttr_In) == 0, "OutLargeData attr must not be In");
248 static constexpr BufferAttr Attr = static_cast<BufferAttr>(A | BufferAttr_In | BufferAttr_FixedSize);
249 using Type = T;
267 250
268template <typename T> 251 /* implicit */ OutLargeData(Type* t) : raw(t) {}
269struct ArgumentTraits<OutCopyHandle<T>> { 252 /* implicit */ OutLargeData(AutoOut<T>& t) : raw(&t.raw) {}
270 static constexpr ArgumentType Type = ArgumentType::OutCopyHandle;
271};
272 253
273template <typename T> 254 Type* Get() const {
274struct ArgumentTraits<OutMoveHandle<T>> { 255 return raw;
275 static constexpr ArgumentType Type = ArgumentType::OutMoveHandle; 256 }
276};
277 257
278template <typename T, int A> 258 Type& operator*() const {
279struct ArgumentTraits<Buffer<T, A>> { 259 return *raw;
280 static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutBuffer : ArgumentType::InBuffer; 260 }
281};
282 261
283template <typename T, int A> 262 Type* operator->() const {
284struct ArgumentTraits<LargeData<T, A>> { 263 return raw;
285 static constexpr ArgumentType Type = (A & BufferAttr_In) == 0 ? ArgumentType::OutLargeData : ArgumentType::InLargeData; 264 }
286};
287 265
288template <typename T> 266private:
289struct ArgumentTraits { 267 Type* raw;
290 static constexpr ArgumentType Type = ArgumentType::InData;
291}; 268};
292// clang-format on 269// clang-format on
293 270
294} // namespace Service 271} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/event.cpp b/src/core/hle/service/event.cpp
new file mode 100644
index 000000000..375660d72
--- /dev/null
+++ b/src/core/hle/service/event.cpp
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_event.h"
5#include "core/hle/service/event.h"
6#include "core/hle/service/kernel_helpers.h"
7
8namespace Service {
9
10Event::Event(KernelHelpers::ServiceContext& ctx) {
11 m_event = ctx.CreateEvent("Event");
12}
13
14Event::~Event() {
15 m_event->GetReadableEvent().Close();
16 m_event->Close();
17}
18
19void Event::Signal() {
20 m_event->Signal();
21}
22
23void Event::Clear() {
24 m_event->Clear();
25}
26
27Kernel::KReadableEvent* Event::GetHandle() {
28 return &m_event->GetReadableEvent();
29}
30
31} // namespace Service
diff --git a/src/core/hle/service/event.h b/src/core/hle/service/event.h
new file mode 100644
index 000000000..cdbc4635a
--- /dev/null
+++ b/src/core/hle/service/event.h
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6namespace Kernel {
7class KEvent;
8class KReadableEvent;
9} // namespace Kernel
10
11namespace Service {
12
13namespace KernelHelpers {
14class ServiceContext;
15}
16
17class Event {
18public:
19 explicit Event(KernelHelpers::ServiceContext& ctx);
20 ~Event();
21
22 void Signal();
23 void Clear();
24
25 Kernel::KReadableEvent* GetHandle();
26
27private:
28 Kernel::KEvent* m_event;
29};
30
31} // 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 @@
15#include "common/settings.h" 15#include "common/settings.h"
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/core.h" 17#include "core/core.h"
18#include "core/file_sys/content_archive.h"
18#include "core/file_sys/errors.h" 19#include "core/file_sys/errors.h"
19#include "core/file_sys/fs_directory.h" 20#include "core/file_sys/fs_directory.h"
20#include "core/file_sys/fs_filesystem.h" 21#include "core/file_sys/fs_filesystem.h"
21#include "core/file_sys/nca_metadata.h" 22#include "core/file_sys/nca_metadata.h"
22#include "core/file_sys/patch_manager.h" 23#include "core/file_sys/patch_manager.h"
24#include "core/file_sys/romfs.h"
23#include "core/file_sys/romfs_factory.h" 25#include "core/file_sys/romfs_factory.h"
24#include "core/file_sys/savedata_factory.h" 26#include "core/file_sys/savedata_factory.h"
25#include "core/file_sys/system_archive/system_archive.h" 27#include "core/file_sys/system_archive/system_archive.h"
@@ -33,18 +35,20 @@
33#include "core/hle/service/filesystem/save_data_controller.h" 35#include "core/hle/service/filesystem/save_data_controller.h"
34#include "core/hle/service/hle_ipc.h" 36#include "core/hle/service/hle_ipc.h"
35#include "core/hle/service/ipc_helpers.h" 37#include "core/hle/service/ipc_helpers.h"
38#include "core/loader/loader.h"
36#include "core/reporter.h" 39#include "core/reporter.h"
37 40
38namespace Service::FileSystem { 41namespace Service::FileSystem {
39enum class FileSystemType : u8 { 42enum class FileSystemProxyType : u8 {
40 Invalid0 = 0, 43 Code = 0,
41 Invalid1 = 1, 44 Rom = 1,
42 Logo = 2, 45 Logo = 2,
43 ContentControl = 3, 46 Control = 3,
44 ContentManual = 4, 47 Manual = 4,
45 ContentMeta = 5, 48 Meta = 5,
46 ContentData = 6, 49 Data = 6,
47 ApplicationPackage = 7, 50 Package = 7,
51 RegisteredUpdate = 8,
48}; 52};
49 53
50class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { 54class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
@@ -357,12 +361,30 @@ void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
357void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) { 361void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
358 IPC::RequestParser rp{ctx}; 362 IPC::RequestParser rp{ctx};
359 363
360 const auto type = rp.PopRaw<FileSystemType>(); 364 struct InputParameters {
361 const auto title_id = rp.PopRaw<u64>(); 365 FileSystemProxyType type;
362 LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id); 366 u64 program_id;
367 };
368 static_assert(sizeof(InputParameters) == 0x10, "InputParameters has wrong size");
369
370 const auto params = rp.PopRaw<InputParameters>();
371 LOG_ERROR(Service_FS, "(STUBBED) called with type={}, program_id={:016X}", params.type,
372 params.program_id);
373
374 // FIXME: many issues with this
375 ASSERT(params.type == FileSystemProxyType::Manual);
376 const auto manual_romfs = romfs_controller->OpenPatchedRomFS(
377 params.program_id, FileSys::ContentRecordType::HtmlDocument);
363 378
364 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 379 ASSERT(manual_romfs != nullptr);
365 rb.Push(ResultUnknown); 380
381 const auto extracted_romfs = FileSys::ExtractRomFS(manual_romfs);
382 ASSERT(extracted_romfs != nullptr);
383
384 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
385 rb.Push(ResultSuccess);
386 rb.PushIpcInterface<IFileSystem>(system, extracted_romfs,
387 SizeGetter::FromStorageId(fsc, FileSys::StorageId::NandUser));
366} 388}
367 389
368void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) { 390void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/glue/time/alarm_worker.cpp b/src/core/hle/service/glue/time/alarm_worker.cpp
index f549ed00a..3ff071f4a 100644
--- a/src/core/hle/service/glue/time/alarm_worker.cpp
+++ b/src/core/hle/service/glue/time/alarm_worker.cpp
@@ -41,7 +41,7 @@ bool AlarmWorker::GetClosestAlarmInfo(Service::PSC::Time::AlarmInfo& out_alarm_i
41 Service::PSC::Time::AlarmInfo alarm_info{}; 41 Service::PSC::Time::AlarmInfo alarm_info{};
42 s64 closest_time{}; 42 s64 closest_time{};
43 43
44 auto res = m_time_m->GetClosestAlarmInfo(is_valid, alarm_info, closest_time); 44 auto res = m_time_m->GetClosestAlarmInfo(&is_valid, &alarm_info, &closest_time);
45 ASSERT(res == ResultSuccess); 45 ASSERT(res == ResultSuccess);
46 46
47 if (is_valid) { 47 if (is_valid) {
@@ -76,6 +76,7 @@ void AlarmWorker::OnPowerStateChanged() {
76 76
77Result AlarmWorker::AttachToClosestAlarmEvent() { 77Result AlarmWorker::AttachToClosestAlarmEvent() {
78 m_time_m->GetClosestAlarmUpdatedEvent(&m_event); 78 m_time_m->GetClosestAlarmUpdatedEvent(&m_event);
79
79 R_SUCCEED(); 80 R_SUCCEED();
80} 81}
81 82
diff --git a/src/core/hle/service/glue/time/alarm_worker.h b/src/core/hle/service/glue/time/alarm_worker.h
index f269cffdb..131d012a6 100644
--- a/src/core/hle/service/glue/time/alarm_worker.h
+++ b/src/core/hle/service/glue/time/alarm_worker.h
@@ -26,7 +26,7 @@ public:
26 26
27 void Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m); 27 void Initialize(std::shared_ptr<Service::PSC::Time::ServiceManager> time_m);
28 28
29 Kernel::KEvent& GetEvent() { 29 Kernel::KReadableEvent& GetEvent() {
30 return *m_event; 30 return *m_event;
31 } 31 }
32 32
@@ -44,7 +44,7 @@ private:
44 KernelHelpers::ServiceContext m_ctx; 44 KernelHelpers::ServiceContext m_ctx;
45 std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m; 45 std::shared_ptr<Service::PSC::Time::ServiceManager> m_time_m;
46 46
47 Kernel::KEvent* m_event{}; 47 Kernel::KReadableEvent* m_event{};
48 Kernel::KEvent* m_timer_event{}; 48 Kernel::KEvent* m_timer_event{};
49 std::shared_ptr<Core::Timing::EventType> m_timer_timing_event; 49 std::shared_ptr<Core::Timing::EventType> m_timer_timing_event;
50 StandardSteadyClockResource& m_steady_clock_resource; 50 StandardSteadyClockResource& m_steady_clock_resource;
diff --git a/src/core/hle/service/glue/time/file_timestamp_worker.cpp b/src/core/hle/service/glue/time/file_timestamp_worker.cpp
index 5a6309549..048ff174c 100644
--- a/src/core/hle/service/glue/time/file_timestamp_worker.cpp
+++ b/src/core/hle/service/glue/time/file_timestamp_worker.cpp
@@ -13,8 +13,8 @@ void FileTimestampWorker::SetFilesystemPosixTime() {
13 Service::PSC::Time::CalendarTime calendar_time{}; 13 Service::PSC::Time::CalendarTime calendar_time{};
14 Service::PSC::Time::CalendarAdditionalInfo additional_info{}; 14 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
15 15
16 if (m_initialized && m_system_clock->GetCurrentTime(time) == ResultSuccess && 16 if (m_initialized && m_system_clock->GetCurrentTime(&time) == ResultSuccess &&
17 m_time_zone->ToCalendarTimeWithMyRule(calendar_time, additional_info, time) == 17 m_time_zone->ToCalendarTimeWithMyRule(&calendar_time, &additional_info, time) ==
18 ResultSuccess) { 18 ResultSuccess) {
19 // TODO IFileSystemProxy::SetCurrentPosixTime 19 // TODO IFileSystemProxy::SetCurrentPosixTime
20 } 20 }
diff --git a/src/core/hle/service/glue/time/manager.cpp b/src/core/hle/service/glue/time/manager.cpp
index b56762941..0c27e8029 100644
--- a/src/core/hle/service/glue/time/manager.cpp
+++ b/src/core/hle/service/glue/time/manager.cpp
@@ -79,18 +79,18 @@ Service::PSC::Time::LocationName GetTimeZoneString(Service::PSC::Time::LocationN
79 auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue()); 79 auto configured_zone = Settings::GetTimeZoneString(Settings::values.time_zone_index.GetValue());
80 80
81 Service::PSC::Time::LocationName configured_name{}; 81 Service::PSC::Time::LocationName configured_name{};
82 std::memcpy(configured_name.name.data(), configured_zone.data(), 82 std::memcpy(configured_name.data(), configured_zone.data(),
83 std::min(configured_name.name.size(), configured_zone.size())); 83 std::min(configured_name.size(), configured_zone.size()));
84 84
85 if (!IsTimeZoneBinaryValid(configured_name)) { 85 if (!IsTimeZoneBinaryValid(configured_name)) {
86 configured_zone = Common::TimeZone::FindSystemTimeZone(); 86 configured_zone = Common::TimeZone::FindSystemTimeZone();
87 configured_name = {}; 87 configured_name = {};
88 std::memcpy(configured_name.name.data(), configured_zone.data(), 88 std::memcpy(configured_name.data(), configured_zone.data(),
89 std::min(configured_name.name.size(), configured_zone.size())); 89 std::min(configured_name.size(), configured_zone.size()));
90 } 90 }
91 91
92 ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!", 92 ASSERT_MSG(IsTimeZoneBinaryValid(configured_name), "Invalid time zone {}!",
93 configured_name.name.data()); 93 configured_name.data());
94 94
95 return configured_name; 95 return configured_name;
96} 96}
@@ -103,7 +103,7 @@ TimeManager::TimeManager(Core::System& system)
103 m_time_m = 103 m_time_m =
104 system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true); 104 system.ServiceManager().GetService<Service::PSC::Time::ServiceManager>("time:m", true);
105 105
106 auto res = m_time_m->GetStaticServiceAsServiceManager(m_time_sm); 106 auto res = m_time_m->GetStaticServiceAsServiceManager(&m_time_sm);
107 ASSERT(res == ResultSuccess); 107 ASSERT(res == ResultSuccess);
108 108
109 m_set_sys = 109 m_set_sys =
@@ -114,10 +114,10 @@ TimeManager::TimeManager(Core::System& system)
114 114
115 m_worker.Initialize(m_time_sm, m_set_sys); 115 m_worker.Initialize(m_time_sm, m_set_sys);
116 116
117 res = m_time_sm->GetStandardUserSystemClock(m_file_timestamp_worker.m_system_clock); 117 res = m_time_sm->GetStandardUserSystemClock(&m_file_timestamp_worker.m_system_clock);
118 ASSERT(res == ResultSuccess); 118 ASSERT(res == ResultSuccess);
119 119
120 res = m_time_sm->GetTimeZoneService(m_file_timestamp_worker.m_time_zone); 120 res = m_time_sm->GetTimeZoneService(&m_file_timestamp_worker.m_time_zone);
121 ASSERT(res == ResultSuccess); 121 ASSERT(res == ResultSuccess);
122 122
123 res = SetupStandardSteadyClockCore(); 123 res = SetupStandardSteadyClockCore();
@@ -161,8 +161,8 @@ TimeManager::TimeManager(Core::System& system)
161 automatic_correction_time_point); 161 automatic_correction_time_point);
162 ASSERT(res == ResultSuccess); 162 ASSERT(res == ResultSuccess);
163 163
164 res = m_time_m->SetupStandardUserSystemClockCore(automatic_correction_time_point, 164 res = m_time_m->SetupStandardUserSystemClockCore(is_automatic_correction_enabled,
165 is_automatic_correction_enabled); 165 automatic_correction_time_point);
166 ASSERT(res == ResultSuccess); 166 ASSERT(res == ResultSuccess);
167 167
168 res = m_time_m->SetupEphemeralNetworkSystemClockCore(); 168 res = m_time_m->SetupEphemeralNetworkSystemClockCore();
@@ -184,12 +184,12 @@ TimeManager::TimeManager(Core::System& system)
184 m_file_timestamp_worker.m_initialized = true; 184 m_file_timestamp_worker.m_initialized = true;
185 185
186 s64 system_clock_time{}; 186 s64 system_clock_time{};
187 if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(system_clock_time) == 187 if (m_file_timestamp_worker.m_system_clock->GetCurrentTime(&system_clock_time) ==
188 ResultSuccess) { 188 ResultSuccess) {
189 Service::PSC::Time::CalendarTime calendar_time{}; 189 Service::PSC::Time::CalendarTime calendar_time{};
190 Service::PSC::Time::CalendarAdditionalInfo calendar_additional{}; 190 Service::PSC::Time::CalendarAdditionalInfo calendar_additional{};
191 if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule( 191 if (m_file_timestamp_worker.m_time_zone->ToCalendarTimeWithMyRule(
192 calendar_time, calendar_additional, system_clock_time) == ResultSuccess) { 192 &calendar_time, &calendar_additional, system_clock_time) == ResultSuccess) {
193 // TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time, 193 // TODO IFileSystemProxy::SetCurrentPosixTime(system_clock_time,
194 // calendar_additional.ut_offset) 194 // calendar_additional.ut_offset)
195 } 195 }
@@ -228,10 +228,9 @@ Result TimeManager::SetupStandardSteadyClockCore() {
228 m_set_sys->SetExternalSteadyClockSourceId(clock_source_id); 228 m_set_sys->SetExternalSteadyClockSourceId(clock_source_id);
229 } 229 }
230 230
231 res = m_time_m->SetupStandardSteadyClockCore(clock_source_id, m_steady_clock_resource.GetTime(), 231 res = m_time_m->SetupStandardSteadyClockCore(
232 external_steady_clock_internal_offset_ns, 232 reset_detected, clock_source_id, m_steady_clock_resource.GetTime(),
233 standard_steady_clock_test_offset_ns, 233 external_steady_clock_internal_offset_ns, standard_steady_clock_test_offset_ns);
234 reset_detected);
235 ASSERT(res == ResultSuccess); 234 ASSERT(res == ResultSuccess);
236 R_SUCCEED(); 235 R_SUCCEED();
237} 236}
@@ -243,14 +242,15 @@ Result TimeManager::SetupTimeZoneServiceCore() {
243 242
244 auto configured_zone = GetTimeZoneString(name); 243 auto configured_zone = GetTimeZoneString(name);
245 244
246 if (configured_zone.name != name.name) { 245 if (configured_zone != name) {
247 m_set_sys->SetDeviceTimeZoneLocationName(configured_zone); 246 m_set_sys->SetDeviceTimeZoneLocationName(configured_zone);
248 name = configured_zone; 247 name = configured_zone;
249 248
250 std::shared_ptr<Service::PSC::Time::SystemClock> local_clock; 249 std::shared_ptr<Service::PSC::Time::SystemClock> local_clock;
251 m_time_sm->GetStandardLocalSystemClock(local_clock); 250 m_time_sm->GetStandardLocalSystemClock(&local_clock);
251
252 Service::PSC::Time::SystemClockContext context{}; 252 Service::PSC::Time::SystemClockContext context{};
253 local_clock->GetSystemClockContext(context); 253 local_clock->GetSystemClockContext(&context);
254 m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(context.steady_time_point); 254 m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(context.steady_time_point);
255 } 255 }
256 256
@@ -267,7 +267,7 @@ Result TimeManager::SetupTimeZoneServiceCore() {
267 res = GetTimeZoneRule(rule_buffer, rule_size, name); 267 res = GetTimeZoneRule(rule_buffer, rule_size, name);
268 ASSERT(res == ResultSuccess); 268 ASSERT(res == ResultSuccess);
269 269
270 res = m_time_m->SetupTimeZoneServiceCore(name, time_point, rule_version, location_count, 270 res = m_time_m->SetupTimeZoneServiceCore(name, rule_version, location_count, time_point,
271 rule_buffer); 271 rule_buffer);
272 ASSERT(res == ResultSuccess); 272 ASSERT(res == ResultSuccess);
273 273
diff --git a/src/core/hle/service/glue/time/static.cpp b/src/core/hle/service/glue/time/static.cpp
index 63b7d91da..f56db76e1 100644
--- a/src/core/hle/service/glue/time/static.cpp
+++ b/src/core/hle/service/glue/time/static.cpp
@@ -3,9 +3,11 @@
3 3
4#include <chrono> 4#include <chrono>
5 5
6#include "common/scope_exit.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/hle/kernel/k_shared_memory.h" 8#include "core/hle/kernel/k_shared_memory.h"
8#include "core/hle/kernel/svc.h" 9#include "core/hle/kernel/svc.h"
10#include "core/hle/service/cmif_serialization.h"
9#include "core/hle/service/glue/time/file_timestamp_worker.h" 11#include "core/hle/service/glue/time/file_timestamp_worker.h"
10#include "core/hle/service/glue/time/static.h" 12#include "core/hle/service/glue/time/static.h"
11#include "core/hle/service/psc/time/errors.h" 13#include "core/hle/service/psc/time/errors.h"
@@ -41,25 +43,25 @@ StaticService::StaticService(Core::System& system_,
41 time->m_steady_clock_resource} { 43 time->m_steady_clock_resource} {
42 // clang-format off 44 // clang-format off
43 static const FunctionInfo functions[] = { 45 static const FunctionInfo functions[] = {
44 {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"}, 46 {0, D<&StaticService::GetStandardUserSystemClock>, "GetStandardUserSystemClock"},
45 {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, 47 {1, D<&StaticService::GetStandardNetworkSystemClock>, "GetStandardNetworkSystemClock"},
46 {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"}, 48 {2, D<&StaticService::GetStandardSteadyClock>, "GetStandardSteadyClock"},
47 {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"}, 49 {3, D<&StaticService::GetTimeZoneService>, "GetTimeZoneService"},
48 {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, 50 {4, D<&StaticService::GetStandardLocalSystemClock>, "GetStandardLocalSystemClock"},
49 {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"}, 51 {5, D<&StaticService::GetEphemeralNetworkSystemClock>, "GetEphemeralNetworkSystemClock"},
50 {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, 52 {20, D<&StaticService::GetSharedMemoryNativeHandle>, "GetSharedMemoryNativeHandle"},
51 {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"}, 53 {50, D<&StaticService::SetStandardSteadyClockInternalOffset>, "SetStandardSteadyClockInternalOffset"},
52 {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"}, 54 {51, D<&StaticService::GetStandardSteadyClockRtcValue>, "GetStandardSteadyClockRtcValue"},
53 {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, 55 {100, D<&StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled>, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
54 {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, 56 {101, D<&StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled>, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
55 {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"}, 57 {102, D<&StaticService::GetStandardUserSystemClockInitialYear>, "GetStandardUserSystemClockInitialYear"},
56 {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, 58 {200, D<&StaticService::IsStandardNetworkSystemClockAccuracySufficient>, "IsStandardNetworkSystemClockAccuracySufficient"},
57 {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, 59 {201, D<&StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime>, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
58 {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, 60 {300, D<&StaticService::CalculateMonotonicSystemClockBaseTimePoint>, "CalculateMonotonicSystemClockBaseTimePoint"},
59 {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"}, 61 {400, D<&StaticService::GetClockSnapshot>, "GetClockSnapshot"},
60 {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, 62 {401, D<&StaticService::GetClockSnapshotFromSystemClockContext>, "GetClockSnapshotFromSystemClockContext"},
61 {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, 63 {500, D<&StaticService::CalculateStandardUserSystemClockDifferenceByUser>, "CalculateStandardUserSystemClockDifferenceByUser"},
62 {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"}, 64 {501, D<&StaticService::CalculateSpanBetween>, "CalculateSpanBetween"},
63 }; 65 };
64 // clang-format on 66 // clang-format on
65 67
@@ -71,314 +73,80 @@ StaticService::StaticService(Core::System& system_,
71 if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock && 73 if (m_setup_info.can_write_local_clock && m_setup_info.can_write_user_clock &&
72 !m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location && 74 !m_setup_info.can_write_network_clock && m_setup_info.can_write_timezone_device_location &&
73 !m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { 75 !m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) {
74 m_time_m->GetStaticServiceAsAdmin(m_wrapped_service); 76 m_time_m->GetStaticServiceAsAdmin(&m_wrapped_service);
75 } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && 77 } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock &&
76 !m_setup_info.can_write_network_clock && 78 !m_setup_info.can_write_network_clock &&
77 !m_setup_info.can_write_timezone_device_location && 79 !m_setup_info.can_write_timezone_device_location &&
78 !m_setup_info.can_write_steady_clock && 80 !m_setup_info.can_write_steady_clock &&
79 !m_setup_info.can_write_uninitialized_clock) { 81 !m_setup_info.can_write_uninitialized_clock) {
80 m_time_m->GetStaticServiceAsUser(m_wrapped_service); 82 m_time_m->GetStaticServiceAsUser(&m_wrapped_service);
81 } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock && 83 } else if (!m_setup_info.can_write_local_clock && !m_setup_info.can_write_user_clock &&
82 !m_setup_info.can_write_network_clock && 84 !m_setup_info.can_write_network_clock &&
83 !m_setup_info.can_write_timezone_device_location && 85 !m_setup_info.can_write_timezone_device_location &&
84 m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) { 86 m_setup_info.can_write_steady_clock && !m_setup_info.can_write_uninitialized_clock) {
85 m_time_m->GetStaticServiceAsRepair(m_wrapped_service); 87 m_time_m->GetStaticServiceAsRepair(&m_wrapped_service);
86 } else { 88 } else {
87 UNREACHABLE(); 89 UNREACHABLE();
88 } 90 }
89 91
90 auto res = m_wrapped_service->GetTimeZoneService(m_time_zone); 92 auto res = m_wrapped_service->GetTimeZoneService(&m_time_zone);
91 ASSERT(res == ResultSuccess); 93 ASSERT(res == ResultSuccess);
92} 94}
93 95
94void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) { 96Result StaticService::GetStandardUserSystemClock(
95 LOG_DEBUG(Service_Time, "called."); 97 OutInterface<Service::PSC::Time::SystemClock> out_service) {
96
97 std::shared_ptr<Service::PSC::Time::SystemClock> service{};
98 auto res = GetStandardUserSystemClock(service);
99
100 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
101 rb.Push(res);
102 rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
103}
104
105void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) {
106 LOG_DEBUG(Service_Time, "called.");
107
108 std::shared_ptr<Service::PSC::Time::SystemClock> service{};
109 auto res = GetStandardNetworkSystemClock(service);
110
111 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
112 rb.Push(res);
113 rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
114}
115
116void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) {
117 LOG_DEBUG(Service_Time, "called.");
118
119 std::shared_ptr<Service::PSC::Time::SteadyClock> service{};
120 auto res = GetStandardSteadyClock(service);
121
122 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
123 rb.Push(res);
124 rb.PushIpcInterface(std::move(service));
125}
126
127void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) {
128 LOG_DEBUG(Service_Time, "called.");
129
130 std::shared_ptr<TimeZoneService> service{};
131 auto res = GetTimeZoneService(service);
132
133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
134 rb.Push(res);
135 rb.PushIpcInterface(std::move(service));
136}
137
138void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) {
139 LOG_DEBUG(Service_Time, "called.");
140
141 std::shared_ptr<Service::PSC::Time::SystemClock> service{};
142 auto res = GetStandardLocalSystemClock(service);
143
144 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
145 rb.Push(res);
146 rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
147}
148
149void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) {
150 LOG_DEBUG(Service_Time, "called.");
151
152 std::shared_ptr<Service::PSC::Time::SystemClock> service{};
153 auto res = GetEphemeralNetworkSystemClock(service);
154
155 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
156 rb.Push(res);
157 rb.PushIpcInterface<Service::PSC::Time::SystemClock>(std::move(service));
158}
159
160void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
161 LOG_DEBUG(Service_Time, "called.");
162
163 Kernel::KSharedMemory* shared_memory{};
164 auto res = GetSharedMemoryNativeHandle(&shared_memory);
165
166 IPC::ResponseBuilder rb{ctx, 2, 1};
167 rb.Push(res);
168 rb.PushCopyObjects(shared_memory);
169}
170
171void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Time, "called.");
173
174 IPC::RequestParser rp{ctx};
175 auto offset_ns{rp.Pop<s64>()};
176
177 auto res = SetStandardSteadyClockInternalOffset(offset_ns);
178
179 IPC::ResponseBuilder rb{ctx, 2};
180 rb.Push(res);
181}
182
183void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) {
184 LOG_DEBUG(Service_Time, "called.");
185
186 s64 rtc_value{};
187 auto res = GetStandardSteadyClockRtcValue(rtc_value);
188
189 IPC::ResponseBuilder rb{ctx, 4};
190 rb.Push(res);
191 rb.Push(rtc_value);
192}
193
194void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(
195 HLERequestContext& ctx) {
196 LOG_DEBUG(Service_Time, "called.");
197
198 bool is_enabled{};
199 auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled);
200
201 IPC::ResponseBuilder rb{ctx, 3};
202 rb.Push(res);
203 rb.Push<bool>(is_enabled);
204}
205
206void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(
207 HLERequestContext& ctx) {
208 LOG_DEBUG(Service_Time, "called.");
209
210 IPC::RequestParser rp{ctx};
211 auto automatic_correction{rp.Pop<bool>()};
212
213 auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
214
215 IPC::ResponseBuilder rb{ctx, 2};
216 rb.Push(res);
217}
218
219void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) {
220 LOG_DEBUG(Service_Time, "called.");
221
222 s32 initial_year{};
223 auto res = GetStandardUserSystemClockInitialYear(initial_year);
224
225 IPC::ResponseBuilder rb{ctx, 3};
226 rb.Push(res);
227 rb.Push(initial_year);
228}
229
230void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
231 LOG_DEBUG(Service_Time, "called."); 98 LOG_DEBUG(Service_Time, "called.");
232 99
233 bool is_sufficient{}; 100 R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service));
234 auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient);
235
236 IPC::ResponseBuilder rb{ctx, 3};
237 rb.Push(res);
238 rb.Push<bool>(is_sufficient);
239} 101}
240 102
241void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 103Result StaticService::GetStandardNetworkSystemClock(
242 HLERequestContext& ctx) { 104 OutInterface<Service::PSC::Time::SystemClock> out_service) {
243 LOG_DEBUG(Service_Time, "called."); 105 LOG_DEBUG(Service_Time, "called.");
244 106
245 Service::PSC::Time::SteadyClockTimePoint time_point{}; 107 R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service));
246 auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
247
248 IPC::ResponseBuilder rb{ctx,
249 2 + sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32)};
250 rb.Push(res);
251 rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
252} 108}
253 109
254void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { 110Result StaticService::GetStandardSteadyClock(
111 OutInterface<Service::PSC::Time::SteadyClock> out_service) {
255 LOG_DEBUG(Service_Time, "called."); 112 LOG_DEBUG(Service_Time, "called.");
256 113
257 IPC::RequestParser rp{ctx}; 114 R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service));
258 auto context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
259
260 s64 time{};
261 auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context);
262
263 IPC::ResponseBuilder rb{ctx, 4};
264 rb.Push(res);
265 rb.Push<s64>(time);
266} 115}
267 116
268void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) { 117Result StaticService::GetTimeZoneService(OutInterface<TimeZoneService> out_service) {
269 LOG_DEBUG(Service_Time, "called."); 118 LOG_DEBUG(Service_Time, "called.");
270 119
271 IPC::RequestParser rp{ctx}; 120 *out_service = std::make_shared<TimeZoneService>(
272 auto type{rp.PopEnum<Service::PSC::Time::TimeType>()}; 121 m_system, m_file_timestamp_worker, m_setup_info.can_write_timezone_device_location,
273 122 m_time_zone);
274 Service::PSC::Time::ClockSnapshot snapshot{}; 123 R_SUCCEED();
275 auto res = GetClockSnapshot(snapshot, type);
276
277 ctx.WriteBuffer(snapshot);
278
279 IPC::ResponseBuilder rb{ctx, 2};
280 rb.Push(res);
281} 124}
282 125
283void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { 126Result StaticService::GetStandardLocalSystemClock(
127 OutInterface<Service::PSC::Time::SystemClock> out_service) {
284 LOG_DEBUG(Service_Time, "called."); 128 LOG_DEBUG(Service_Time, "called.");
285 129
286 IPC::RequestParser rp{ctx}; 130 R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service));
287 auto clock_type{rp.PopEnum<Service::PSC::Time::TimeType>()};
288 [[maybe_unused]] auto alignment{rp.Pop<u32>()};
289 auto user_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
290 auto network_context{rp.PopRaw<Service::PSC::Time::SystemClockContext>()};
291
292 Service::PSC::Time::ClockSnapshot snapshot{};
293 auto res =
294 GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type);
295
296 ctx.WriteBuffer(snapshot);
297
298 IPC::ResponseBuilder rb{ctx, 2};
299 rb.Push(res);
300} 131}
301 132
302void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser( 133Result StaticService::GetEphemeralNetworkSystemClock(
303 HLERequestContext& ctx) { 134 OutInterface<Service::PSC::Time::SystemClock> out_service) {
304 LOG_DEBUG(Service_Time, "called."); 135 LOG_DEBUG(Service_Time, "called.");
305 136
306 Service::PSC::Time::ClockSnapshot a{}; 137 R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service));
307 Service::PSC::Time::ClockSnapshot b{};
308
309 auto a_buffer{ctx.ReadBuffer(0)};
310 auto b_buffer{ctx.ReadBuffer(1)};
311
312 std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
313 std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
314
315 s64 difference{};
316 auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b);
317
318 IPC::ResponseBuilder rb{ctx, 4};
319 rb.Push(res);
320 rb.Push(difference);
321} 138}
322 139
323void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) { 140Result StaticService::GetSharedMemoryNativeHandle(
141 OutCopyHandle<Kernel::KSharedMemory> out_shared_memory) {
324 LOG_DEBUG(Service_Time, "called."); 142 LOG_DEBUG(Service_Time, "called.");
325 143
326 Service::PSC::Time::ClockSnapshot a{};
327 Service::PSC::Time::ClockSnapshot b{};
328
329 auto a_buffer{ctx.ReadBuffer(0)};
330 auto b_buffer{ctx.ReadBuffer(1)};
331
332 std::memcpy(&a, a_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
333 std::memcpy(&b, b_buffer.data(), sizeof(Service::PSC::Time::ClockSnapshot));
334
335 s64 time{};
336 auto res = CalculateSpanBetween(time, a, b);
337
338 IPC::ResponseBuilder rb{ctx, 4};
339 rb.Push(res);
340 rb.Push(time);
341}
342
343// =============================== Implementations ===========================
344
345Result StaticService::GetStandardUserSystemClock(
346 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
347 R_RETURN(m_wrapped_service->GetStandardUserSystemClock(out_service));
348}
349
350Result StaticService::GetStandardNetworkSystemClock(
351 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
352 R_RETURN(m_wrapped_service->GetStandardNetworkSystemClock(out_service));
353}
354
355Result StaticService::GetStandardSteadyClock(
356 std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service) {
357 R_RETURN(m_wrapped_service->GetStandardSteadyClock(out_service));
358}
359
360Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) {
361 out_service = std::make_shared<TimeZoneService>(m_system, m_file_timestamp_worker,
362 m_setup_info.can_write_timezone_device_location,
363 m_time_zone);
364 R_SUCCEED();
365}
366
367Result StaticService::GetStandardLocalSystemClock(
368 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
369 R_RETURN(m_wrapped_service->GetStandardLocalSystemClock(out_service));
370}
371
372Result StaticService::GetEphemeralNetworkSystemClock(
373 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service) {
374 R_RETURN(m_wrapped_service->GetEphemeralNetworkSystemClock(out_service));
375}
376
377Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) {
378 R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory)); 144 R_RETURN(m_wrapped_service->GetSharedMemoryNativeHandle(out_shared_memory));
379} 145}
380 146
381Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) { 147Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
148 LOG_DEBUG(Service_Time, "called. offset_ns={}", offset_ns);
149
382 R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied); 150 R_UNLESS(m_setup_info.can_write_steady_clock, Service::PSC::Time::ResultPermissionDenied);
383 151
384 R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset( 152 R_RETURN(m_set_sys->SetExternalSteadyClockInternalOffset(
@@ -386,62 +154,92 @@ Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
386 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count())); 154 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()));
387} 155}
388 156
389Result StaticService::GetStandardSteadyClockRtcValue(s64& out_rtc_value) { 157Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
390 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(out_rtc_value)); 158 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); });
159
160 R_RETURN(m_standard_steady_clock_resource.GetRtcTimeInSeconds(*out_rtc_value));
391} 161}
392 162
393Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled( 163Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
394 bool& out_automatic_correction) { 164 Out<bool> out_automatic_correction) {
165 SCOPE_EXIT({
166 LOG_DEBUG(Service_Time, "called. out_automatic_correction={}", *out_automatic_correction);
167 });
168
395 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled( 169 R_RETURN(m_wrapped_service->IsStandardUserSystemClockAutomaticCorrectionEnabled(
396 out_automatic_correction)); 170 out_automatic_correction));
397} 171}
398 172
399Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( 173Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
400 bool automatic_correction) { 174 bool automatic_correction) {
175 LOG_DEBUG(Service_Time, "called. automatic_correction={}", automatic_correction);
176
401 R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled( 177 R_RETURN(m_wrapped_service->SetStandardUserSystemClockAutomaticCorrectionEnabled(
402 automatic_correction)); 178 automatic_correction));
403} 179}
404 180
405Result StaticService::GetStandardUserSystemClockInitialYear(s32& out_year) { 181Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
406 out_year = GetSettingsItemValue<s32>(m_set_sys, "time", "standard_user_clock_initial_year"); 182 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_year={}", *out_year); });
183
184 *out_year = GetSettingsItemValue<s32>(m_set_sys, "time", "standard_user_clock_initial_year");
407 R_SUCCEED(); 185 R_SUCCEED();
408} 186}
409 187
410Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) { 188Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
189 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); });
190
411 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient)); 191 R_RETURN(m_wrapped_service->IsStandardNetworkSystemClockAccuracySufficient(out_is_sufficient));
412} 192}
413 193
414Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 194Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
415 Service::PSC::Time::SteadyClockTimePoint& out_time_point) { 195 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
196 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); });
197
416 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 198 R_RETURN(m_wrapped_service->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
417 out_time_point)); 199 out_time_point));
418} 200}
419 201
420Result StaticService::CalculateMonotonicSystemClockBaseTimePoint( 202Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(
421 s64& out_time, Service::PSC::Time::SystemClockContext& context) { 203 Out<s64> out_time, Service::PSC::Time::SystemClockContext& context) {
204 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); });
205
422 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context)); 206 R_RETURN(m_wrapped_service->CalculateMonotonicSystemClockBaseTimePoint(out_time, context));
423} 207}
424 208
425Result StaticService::GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot, 209Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot,
426 Service::PSC::Time::TimeType type) { 210 Service::PSC::Time::TimeType type) {
211 SCOPE_EXIT(
212 { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); });
213
427 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type)); 214 R_RETURN(m_wrapped_service->GetClockSnapshot(out_snapshot, type));
428} 215}
429 216
430Result StaticService::GetClockSnapshotFromSystemClockContext( 217Result StaticService::GetClockSnapshotFromSystemClockContext(
431 Service::PSC::Time::ClockSnapshot& out_snapshot, 218 Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
432 Service::PSC::Time::SystemClockContext& user_context, 219 Service::PSC::Time::SystemClockContext& user_context,
433 Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type) { 220 Service::PSC::Time::SystemClockContext& network_context) {
434 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(out_snapshot, user_context, 221 SCOPE_EXIT({
435 network_context, type)); 222 LOG_DEBUG(Service_Time,
223 "called. type={} out_snapshot={} user_context={} network_context={}", type,
224 *out_snapshot, user_context, network_context);
225 });
226
227 R_RETURN(m_wrapped_service->GetClockSnapshotFromSystemClockContext(
228 type, out_snapshot, user_context, network_context));
436} 229}
437 230
438Result StaticService::CalculateStandardUserSystemClockDifferenceByUser( 231Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_time,
439 s64& out_time, Service::PSC::Time::ClockSnapshot& a, Service::PSC::Time::ClockSnapshot& b) { 232 InClockSnapshot a,
233 InClockSnapshot b) {
234 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); });
235
440 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b)); 236 R_RETURN(m_wrapped_service->CalculateStandardUserSystemClockDifferenceByUser(out_time, a, b));
441} 237}
442 238
443Result StaticService::CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a, 239Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
444 Service::PSC::Time::ClockSnapshot& b) { 240 InClockSnapshot b) {
241 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); });
242
445 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b)); 243 R_RETURN(m_wrapped_service->CalculateSpanBetween(out_time, a, b));
446} 244}
447 245
diff --git a/src/core/hle/service/glue/time/static.h b/src/core/hle/service/glue/time/static.h
index 75fe4e2cd..d3cc0fdd6 100644
--- a/src/core/hle/service/glue/time/static.h
+++ b/src/core/hle/service/glue/time/static.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/glue/time/manager.h" 8#include "core/hle/service/glue/time/manager.h"
8#include "core/hle/service/glue/time/time_zone.h" 9#include "core/hle/service/glue/time/time_zone.h"
9#include "core/hle/service/psc/time/common.h" 10#include "core/hle/service/psc/time/common.h"
@@ -29,6 +30,10 @@ class FileTimestampWorker;
29class StandardSteadyClockResource; 30class StandardSteadyClockResource;
30 31
31class StaticService final : public ServiceFramework<StaticService> { 32class StaticService final : public ServiceFramework<StaticService> {
33 using InClockSnapshot = InLargeData<Service::PSC::Time::ClockSnapshot, BufferAttr_HipcPointer>;
34 using OutClockSnapshot =
35 OutLargeData<Service::PSC::Time::ClockSnapshot, BufferAttr_HipcPointer>;
36
32public: 37public:
33 explicit StaticService(Core::System& system, 38 explicit StaticService(Core::System& system,
34 Service::PSC::Time::StaticServiceSetupInfo setup_info, 39 Service::PSC::Time::StaticServiceSetupInfo setup_info,
@@ -36,65 +41,34 @@ public:
36 41
37 ~StaticService() override = default; 42 ~StaticService() override = default;
38 43
39 Result GetStandardUserSystemClock( 44 Result GetStandardUserSystemClock(OutInterface<Service::PSC::Time::SystemClock> out_service);
40 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); 45 Result GetStandardNetworkSystemClock(OutInterface<Service::PSC::Time::SystemClock> out_service);
41 Result GetStandardNetworkSystemClock( 46 Result GetStandardSteadyClock(OutInterface<Service::PSC::Time::SteadyClock> out_service);
42 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); 47 Result GetTimeZoneService(OutInterface<TimeZoneService> out_service);
43 Result GetStandardSteadyClock(std::shared_ptr<Service::PSC::Time::SteadyClock>& out_service); 48 Result GetStandardLocalSystemClock(OutInterface<Service::PSC::Time::SystemClock> out_service);
44 Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service);
45 Result GetStandardLocalSystemClock(
46 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service);
47 Result GetEphemeralNetworkSystemClock( 49 Result GetEphemeralNetworkSystemClock(
48 std::shared_ptr<Service::PSC::Time::SystemClock>& out_service); 50 OutInterface<Service::PSC::Time::SystemClock> out_service);
49 Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory); 51 Result GetSharedMemoryNativeHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory);
50 Result SetStandardSteadyClockInternalOffset(s64 offset); 52 Result SetStandardSteadyClockInternalOffset(s64 offset_ns);
51 Result GetStandardSteadyClockRtcValue(s64& out_rtc_value); 53 Result GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value);
52 Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_automatic_correction); 54 Result IsStandardUserSystemClockAutomaticCorrectionEnabled(Out<bool> out_is_enabled);
53 Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction); 55 Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction);
54 Result GetStandardUserSystemClockInitialYear(s32& out_year); 56 Result GetStandardUserSystemClockInitialYear(Out<s32> out_year);
55 Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient); 57 Result IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient);
56 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 58 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
57 Service::PSC::Time::SteadyClockTimePoint& out_time_point); 59 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point);
58 Result CalculateMonotonicSystemClockBaseTimePoint( 60 Result CalculateMonotonicSystemClockBaseTimePoint(
59 s64& out_time, Service::PSC::Time::SystemClockContext& context); 61 Out<s64> out_time, Service::PSC::Time::SystemClockContext& context);
60 Result GetClockSnapshot(Service::PSC::Time::ClockSnapshot& out_snapshot, 62 Result GetClockSnapshot(OutClockSnapshot out_snapshot, Service::PSC::Time::TimeType type);
61 Service::PSC::Time::TimeType type);
62 Result GetClockSnapshotFromSystemClockContext( 63 Result GetClockSnapshotFromSystemClockContext(
63 Service::PSC::Time::ClockSnapshot& out_snapshot, 64 Service::PSC::Time::TimeType type, OutClockSnapshot out_snapshot,
64 Service::PSC::Time::SystemClockContext& user_context, 65 Service::PSC::Time::SystemClockContext& user_context,
65 Service::PSC::Time::SystemClockContext& network_context, Service::PSC::Time::TimeType type); 66 Service::PSC::Time::SystemClockContext& network_context);
66 Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, 67 Result CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
67 Service::PSC::Time::ClockSnapshot& a, 68 InClockSnapshot a, InClockSnapshot b);
68 Service::PSC::Time::ClockSnapshot& b); 69 Result CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, InClockSnapshot b);
69 Result CalculateSpanBetween(s64& out_time, Service::PSC::Time::ClockSnapshot& a,
70 Service::PSC::Time::ClockSnapshot& b);
71 70
72private: 71private:
73 Result GetClockSnapshotImpl(Service::PSC::Time::ClockSnapshot& out_snapshot,
74 Service::PSC::Time::SystemClockContext& user_context,
75 Service::PSC::Time::SystemClockContext& network_context,
76 Service::PSC::Time::TimeType type);
77
78 void Handle_GetStandardUserSystemClock(HLERequestContext& ctx);
79 void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx);
80 void Handle_GetStandardSteadyClock(HLERequestContext& ctx);
81 void Handle_GetTimeZoneService(HLERequestContext& ctx);
82 void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx);
83 void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx);
84 void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx);
85 void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx);
86 void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx);
87 void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
88 void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
89 void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx);
90 void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
91 void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
92 void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
93 void Handle_GetClockSnapshot(HLERequestContext& ctx);
94 void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
95 void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
96 void Handle_CalculateSpanBetween(HLERequestContext& ctx);
97
98 Core::System& m_system; 72 Core::System& m_system;
99 73
100 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; 74 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp
index 503c327dd..98d928697 100644
--- a/src/core/hle/service/glue/time/time_zone.cpp
+++ b/src/core/hle/service/glue/time/time_zone.cpp
@@ -3,8 +3,10 @@
3 3
4#include <chrono> 4#include <chrono>
5 5
6#include "common/scope_exit.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/hle/kernel/svc.h" 8#include "core/hle/kernel/svc.h"
9#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/glue/time/file_timestamp_worker.h" 10#include "core/hle/service/glue/time/file_timestamp_worker.h"
9#include "core/hle/service/glue/time/time_zone.h" 11#include "core/hle/service/glue/time/time_zone.h"
10#include "core/hle/service/glue/time/time_zone_binary.h" 12#include "core/hle/service/glue/time/time_zone_binary.h"
@@ -28,20 +30,20 @@ TimeZoneService::TimeZoneService(
28 m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} { 30 m_wrapped_service{std::move(time_zone_service)}, m_operation_event{m_system} {
29 // clang-format off 31 // clang-format off
30 static const FunctionInfo functions[] = { 32 static const FunctionInfo functions[] = {
31 {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"}, 33 {0, D<&TimeZoneService::GetDeviceLocationName>, "GetDeviceLocationName"},
32 {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"}, 34 {1, D<&TimeZoneService::SetDeviceLocationName>, "SetDeviceLocationName"},
33 {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"}, 35 {2, D<&TimeZoneService::GetTotalLocationNameCount>, "GetTotalLocationNameCount"},
34 {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"}, 36 {3, D<&TimeZoneService::LoadLocationNameList>, "LoadLocationNameList"},
35 {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"}, 37 {4, D<&TimeZoneService::LoadTimeZoneRule>, "LoadTimeZoneRule"},
36 {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, 38 {5, D<&TimeZoneService::GetTimeZoneRuleVersion>, "GetTimeZoneRuleVersion"},
37 {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"}, 39 {6, D<&TimeZoneService::GetDeviceLocationNameAndUpdatedTime>, "GetDeviceLocationNameAndUpdatedTime"},
38 {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"}, 40 {7, D<&TimeZoneService::SetDeviceLocationNameWithTimeZoneRule>, "SetDeviceLocationNameWithTimeZoneRule"},
39 {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"}, 41 {8, D<&TimeZoneService::ParseTimeZoneBinary>, "ParseTimeZoneBinary"},
40 {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"}, 42 {20, D<&TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle>, "GetDeviceLocationNameOperationEventReadableHandle"},
41 {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"}, 43 {100, D<&TimeZoneService::ToCalendarTime>, "ToCalendarTime"},
42 {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, 44 {101, D<&TimeZoneService::ToCalendarTimeWithMyRule>, "ToCalendarTimeWithMyRule"},
43 {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"}, 45 {201, D<&TimeZoneService::ToPosixTime>, "ToPosixTime"},
44 {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, 46 {202, D<&TimeZoneService::ToPosixTimeWithMyRule>, "ToPosixTimeWithMyRule"},
45 }; 47 };
46 // clang-format on 48 // clang-format on
47 RegisterHandlers(functions); 49 RegisterHandlers(functions);
@@ -53,220 +55,16 @@ TimeZoneService::TimeZoneService(
53 55
54TimeZoneService::~TimeZoneService() = default; 56TimeZoneService::~TimeZoneService() = default;
55 57
56void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) { 58Result TimeZoneService::GetDeviceLocationName(
57 LOG_DEBUG(Service_Time, "called."); 59 Out<Service::PSC::Time::LocationName> out_location_name) {
58 60 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); });
59 Service::PSC::Time::LocationName name{};
60 auto res = GetDeviceLocationName(name);
61
62 IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::LocationName) / sizeof(u32)};
63 rb.Push(res);
64 rb.PushRaw<Service::PSC::Time::LocationName>(name);
65}
66
67void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) {
68 LOG_DEBUG(Service_Time, "called.");
69
70 IPC::RequestParser rp{ctx};
71 auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
72
73 auto res = SetDeviceLocation(name);
74
75 IPC::ResponseBuilder rb{ctx, 2};
76 rb.Push(res);
77}
78
79void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) {
80 LOG_DEBUG(Service_Time, "called.");
81
82 u32 count{};
83 auto res = GetTotalLocationNameCount(count);
84
85 IPC::ResponseBuilder rb{ctx, 3};
86 rb.Push(res);
87 rb.Push(count);
88}
89
90void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) {
91 LOG_DEBUG(Service_Time, "called.");
92
93 IPC::RequestParser rp{ctx};
94 auto index{rp.Pop<u32>()};
95
96 auto max_names{ctx.GetWriteBufferSize() / sizeof(Service::PSC::Time::LocationName)};
97
98 std::vector<Service::PSC::Time::LocationName> names{};
99 u32 count{};
100 auto res = LoadLocationNameList(count, names, max_names, index);
101
102 ctx.WriteBuffer(names);
103
104 IPC::ResponseBuilder rb{ctx, 3};
105 rb.Push(res);
106 rb.Push(count);
107}
108
109void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) {
110 LOG_DEBUG(Service_Time, "called.");
111
112 IPC::RequestParser rp{ctx};
113 auto name{rp.PopRaw<Service::PSC::Time::LocationName>()};
114
115 Tz::Rule rule{};
116 auto res = LoadTimeZoneRule(rule, name);
117
118 ctx.WriteBuffer(rule);
119
120 IPC::ResponseBuilder rb{ctx, 2};
121 rb.Push(res);
122}
123
124void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) {
125 LOG_DEBUG(Service_Time, "called.");
126
127 Service::PSC::Time::RuleVersion rule_version{};
128 auto res = GetTimeZoneRuleVersion(rule_version);
129
130 IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::PSC::Time::RuleVersion) / sizeof(u32)};
131 rb.Push(res);
132 rb.PushRaw<Service::PSC::Time::RuleVersion>(rule_version);
133}
134
135void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) {
136 LOG_DEBUG(Service_Time, "called.");
137
138 Service::PSC::Time::LocationName name{};
139 Service::PSC::Time::SteadyClockTimePoint time_point{};
140 auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name);
141
142 IPC::ResponseBuilder rb{ctx,
143 2 + (sizeof(Service::PSC::Time::LocationName) / sizeof(u32)) +
144 (sizeof(Service::PSC::Time::SteadyClockTimePoint) / sizeof(u32))};
145 rb.Push(res);
146 rb.PushRaw<Service::PSC::Time::LocationName>(name);
147 rb.PushRaw<Service::PSC::Time::SteadyClockTimePoint>(time_point);
148}
149
150void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) {
151 LOG_DEBUG(Service_Time, "called.");
152
153 auto res = SetDeviceLocationNameWithTimeZoneRule();
154
155 IPC::ResponseBuilder rb{ctx, 2};
156 rb.Push(res);
157}
158
159void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) {
160 LOG_DEBUG(Service_Time, "called.");
161
162 IPC::ResponseBuilder rb{ctx, 2};
163 rb.Push(Service::PSC::Time::ResultNotImplemented);
164}
165
166void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle(
167 HLERequestContext& ctx) {
168 LOG_DEBUG(Service_Time, "called.");
169 61
170 Kernel::KEvent* event{};
171 auto res = GetDeviceLocationNameOperationEventReadableHandle(&event);
172
173 IPC::ResponseBuilder rb{ctx, 2, 1};
174 rb.Push(res);
175 rb.PushCopyObjects(event->GetReadableEvent());
176}
177
178void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) {
179 LOG_DEBUG(Service_Time, "called.");
180
181 IPC::RequestParser rp{ctx};
182 auto time{rp.Pop<s64>()};
183
184 auto rule_buffer{ctx.ReadBuffer()};
185 Tz::Rule rule{};
186 std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule));
187
188 Service::PSC::Time::CalendarTime calendar_time{};
189 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
190 auto res = ToCalendarTime(calendar_time, additional_info, time, rule);
191
192 IPC::ResponseBuilder rb{ctx,
193 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) +
194 (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))};
195 rb.Push(res);
196 rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time);
197 rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info);
198}
199
200void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
201 IPC::RequestParser rp{ctx};
202 auto time{rp.Pop<s64>()};
203
204 LOG_DEBUG(Service_Time, "called. time={}", time);
205
206 Service::PSC::Time::CalendarTime calendar_time{};
207 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
208 auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time);
209
210 IPC::ResponseBuilder rb{ctx,
211 2 + (sizeof(Service::PSC::Time::CalendarTime) / sizeof(u32)) +
212 (sizeof(Service::PSC::Time::CalendarAdditionalInfo) / sizeof(u32))};
213 rb.Push(res);
214 rb.PushRaw<Service::PSC::Time::CalendarTime>(calendar_time);
215 rb.PushRaw<Service::PSC::Time::CalendarAdditionalInfo>(additional_info);
216}
217
218void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) {
219 IPC::RequestParser rp{ctx};
220 auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()};
221
222 LOG_DEBUG(Service_Time, "called. calendar year {} month {} day {} hour {} minute {} second {}",
223 calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute,
224 calendar.second);
225
226 auto binary{ctx.ReadBuffer()};
227
228 Tz::Rule rule{};
229 std::memcpy(&rule, binary.data(), sizeof(Tz::Rule));
230
231 u32 count{};
232 std::array<s64, 2> times{};
233 u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
234
235 auto res = ToPosixTime(count, times, times_count, calendar, rule);
236
237 ctx.WriteBuffer(times);
238
239 IPC::ResponseBuilder rb{ctx, 3};
240 rb.Push(res);
241 rb.Push(count);
242}
243
244void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) {
245 LOG_DEBUG(Service_Time, "called.");
246
247 IPC::RequestParser rp{ctx};
248 auto calendar{rp.PopRaw<Service::PSC::Time::CalendarTime>()};
249
250 u32 count{};
251 std::array<s64, 2> times{};
252 u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
253
254 auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar);
255
256 ctx.WriteBuffer(times);
257
258 IPC::ResponseBuilder rb{ctx, 3};
259 rb.Push(res);
260 rb.Push(count);
261}
262
263// =============================== Implementations ===========================
264
265Result TimeZoneService::GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name) {
266 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name)); 62 R_RETURN(m_wrapped_service->GetDeviceLocationName(out_location_name));
267} 63}
268 64
269Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& location_name) { 65Result TimeZoneService::SetDeviceLocationName(Service::PSC::Time::LocationName& location_name) {
66 LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
67
270 R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); 68 R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
271 R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound); 69 R_UNLESS(IsTimeZoneBinaryValid(location_name), Service::PSC::Time::ResultTimeZoneNotFound);
272 70
@@ -282,7 +80,7 @@ Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& loca
282 80
283 Service::PSC::Time::SteadyClockTimePoint time_point{}; 81 Service::PSC::Time::SteadyClockTimePoint time_point{};
284 Service::PSC::Time::LocationName name{}; 82 Service::PSC::Time::LocationName name{};
285 R_TRY(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(time_point, name)); 83 R_TRY(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(&name, &time_point));
286 84
287 m_set_sys->SetDeviceTimeZoneLocationName(name); 85 m_set_sys->SetDeviceTimeZoneLocationName(name);
288 m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point); 86 m_set_sys->SetDeviceTimeZoneLocationUpdatedTime(time_point);
@@ -294,19 +92,27 @@ Result TimeZoneService::SetDeviceLocation(Service::PSC::Time::LocationName& loca
294 R_SUCCEED(); 92 R_SUCCEED();
295} 93}
296 94
297Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) { 95Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
96 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); });
97
298 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count)); 98 R_RETURN(m_wrapped_service->GetTotalLocationNameCount(out_count));
299} 99}
300 100
301Result TimeZoneService::LoadLocationNameList( 101Result TimeZoneService::LoadLocationNameList(
302 u32& out_count, std::vector<Service::PSC::Time::LocationName>& out_names, size_t max_names, 102 Out<u32> out_count,
303 u32 index) { 103 OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) {
104 SCOPE_EXIT({
105 LOG_DEBUG(Service_Time, "called. index={} out_count={} out_names[0]={} out_names[1]={}",
106 index, *out_count, out_names[0], out_names[1]);
107 });
108
304 std::scoped_lock l{m_mutex}; 109 std::scoped_lock l{m_mutex};
305 R_RETURN(GetTimeZoneLocationList(out_count, out_names, max_names, index)); 110 R_RETURN(GetTimeZoneLocationList(*out_count, out_names, out_names.size(), index));
306} 111}
307 112
308Result TimeZoneService::LoadTimeZoneRule(Tz::Rule& out_rule, 113Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, Service::PSC::Time::LocationName& name) {
309 Service::PSC::Time::LocationName& name) { 114 LOG_DEBUG(Service_Time, "called. name={}", name);
115
310 std::scoped_lock l{m_mutex}; 116 std::scoped_lock l{m_mutex};
311 std::span<const u8> binary{}; 117 std::span<const u8> binary{};
312 size_t binary_size{}; 118 size_t binary_size{};
@@ -314,23 +120,43 @@ Result TimeZoneService::LoadTimeZoneRule(Tz::Rule& out_rule,
314 R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary)); 120 R_RETURN(m_wrapped_service->ParseTimeZoneBinary(out_rule, binary));
315} 121}
316 122
317Result TimeZoneService::GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version) { 123Result TimeZoneService::GetTimeZoneRuleVersion(
124 Out<Service::PSC::Time::RuleVersion> out_rule_version) {
125 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); });
126
318 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version)); 127 R_RETURN(m_wrapped_service->GetTimeZoneRuleVersion(out_rule_version));
319} 128}
320 129
321Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime( 130Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
322 Service::PSC::Time::SteadyClockTimePoint& out_time_point, 131 Out<Service::PSC::Time::LocationName> location_name,
323 Service::PSC::Time::LocationName& location_name) { 132 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point) {
324 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(out_time_point, location_name)); 133 SCOPE_EXIT({
134 LOG_DEBUG(Service_Time, "called. location_name={} out_time_point={}", *location_name,
135 *out_time_point);
136 });
137
138 R_RETURN(m_wrapped_service->GetDeviceLocationNameAndUpdatedTime(location_name, out_time_point));
325} 139}
326 140
327Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule() { 141Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(
142 Service::PSC::Time::LocationName& location_name, InBuffer<BufferAttr_HipcAutoSelect> binary) {
143 LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
144
328 R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied); 145 R_UNLESS(m_can_write_timezone_device_location, Service::PSC::Time::ResultPermissionDenied);
329 R_RETURN(Service::PSC::Time::ResultNotImplemented); 146 R_RETURN(Service::PSC::Time::ResultNotImplemented);
330} 147}
331 148
149Result TimeZoneService::ParseTimeZoneBinary(OutRule out_rule,
150 InBuffer<BufferAttr_HipcAutoSelect> binary) {
151 LOG_DEBUG(Service_Time, "called.");
152
153 R_RETURN(Service::PSC::Time::ResultNotImplemented);
154}
155
332Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle( 156Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
333 Kernel::KEvent** out_event) { 157 OutCopyHandle<Kernel::KReadableEvent> out_event) {
158 LOG_DEBUG(Service_Time, "called.");
159
334 if (!operation_event_initialized) { 160 if (!operation_event_initialized) {
335 operation_event_initialized = false; 161 operation_event_initialized = false;
336 162
@@ -342,36 +168,56 @@ Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
342 g_list_nodes.push_back(m_operation_event); 168 g_list_nodes.push_back(m_operation_event);
343 } 169 }
344 170
345 *out_event = m_operation_event.m_event; 171 *out_event = &m_operation_event.m_event->GetReadableEvent();
346 R_SUCCEED(); 172 R_SUCCEED();
347} 173}
348 174
349Result TimeZoneService::ToCalendarTime( 175Result TimeZoneService::ToCalendarTime(
350 Service::PSC::Time::CalendarTime& out_calendar_time, 176 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
351 Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule) { 177 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule) {
178 SCOPE_EXIT({
179 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
180 *out_calendar_time, *out_additional_info);
181 });
182
352 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule)); 183 R_RETURN(m_wrapped_service->ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
353} 184}
354 185
355Result TimeZoneService::ToCalendarTimeWithMyRule( 186Result TimeZoneService::ToCalendarTimeWithMyRule(
356 Service::PSC::Time::CalendarTime& out_calendar_time, 187 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
357 Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time) { 188 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time) {
189 SCOPE_EXIT({
190 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
191 *out_calendar_time, *out_additional_info);
192 });
193
358 R_RETURN( 194 R_RETURN(
359 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time)); 195 m_wrapped_service->ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
360} 196}
361 197
362Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, 198Result TimeZoneService::ToPosixTime(Out<u32> out_count,
363 u32 out_times_count, 199 OutArray<s64, BufferAttr_HipcPointer> out_times,
364 Service::PSC::Time::CalendarTime& calendar_time, 200 const Service::PSC::Time::CalendarTime& calendar_time,
365 Tz::Rule& rule) { 201 InRule rule) {
366 R_RETURN( 202 SCOPE_EXIT({
367 m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule)); 203 LOG_DEBUG(Service_Time,
204 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
205 calendar_time, *out_count, out_times[0], out_times[1]);
206 });
207
208 R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule));
368} 209}
369 210
370Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, 211Result TimeZoneService::ToPosixTimeWithMyRule(
371 u32 out_times_count, 212 Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
372 Service::PSC::Time::CalendarTime& calendar_time) { 213 const Service::PSC::Time::CalendarTime& calendar_time) {
373 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count, 214 SCOPE_EXIT({
374 calendar_time)); 215 LOG_DEBUG(Service_Time,
216 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
217 calendar_time, *out_count, out_times[0], out_times[1]);
218 });
219
220 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time));
375} 221}
376 222
377} // namespace Service::Glue::Time 223} // 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 3c8ae4bf8..9c1530966 100644
--- a/src/core/hle/service/glue/time/time_zone.h
+++ b/src/core/hle/service/glue/time/time_zone.h
@@ -8,6 +8,7 @@
8#include <span> 8#include <span>
9#include <vector> 9#include <vector>
10 10
11#include "core/hle/service/cmif_types.h"
11#include "core/hle/service/ipc_helpers.h" 12#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/psc/time/common.h" 13#include "core/hle/service/psc/time/common.h"
13#include "core/hle/service/server_manager.h" 14#include "core/hle/service/server_manager.h"
@@ -33,6 +34,9 @@ namespace Service::Glue::Time {
33class FileTimestampWorker; 34class FileTimestampWorker;
34 35
35class TimeZoneService final : public ServiceFramework<TimeZoneService> { 36class TimeZoneService final : public ServiceFramework<TimeZoneService> {
37 using InRule = InLargeData<Tz::Rule, BufferAttr_HipcMapAlias>;
38 using OutRule = OutLargeData<Tz::Rule, BufferAttr_HipcMapAlias>;
39
36public: 40public:
37 explicit TimeZoneService( 41 explicit TimeZoneService(
38 Core::System& system, FileTimestampWorker& file_timestamp_worker, 42 Core::System& system, FileTimestampWorker& file_timestamp_worker,
@@ -41,46 +45,35 @@ public:
41 45
42 ~TimeZoneService() override; 46 ~TimeZoneService() override;
43 47
44 Result GetDeviceLocationName(Service::PSC::Time::LocationName& out_location_name); 48 Result GetDeviceLocationName(Out<Service::PSC::Time::LocationName> out_location_name);
45 Result SetDeviceLocation(Service::PSC::Time::LocationName& location_name); 49 Result SetDeviceLocationName(Service::PSC::Time::LocationName& location_name);
46 Result GetTotalLocationNameCount(u32& out_count); 50 Result GetTotalLocationNameCount(Out<u32> out_count);
47 Result LoadLocationNameList(u32& out_count, 51 Result LoadLocationNameList(
48 std::vector<Service::PSC::Time::LocationName>& out_names, 52 Out<u32> out_count,
49 size_t max_names, u32 index); 53 OutArray<Service::PSC::Time::LocationName, BufferAttr_HipcMapAlias> out_names, u32 index);
50 Result LoadTimeZoneRule(Tz::Rule& out_rule, Service::PSC::Time::LocationName& name); 54 Result LoadTimeZoneRule(OutRule out_rule, Service::PSC::Time::LocationName& location_name);
51 Result GetTimeZoneRuleVersion(Service::PSC::Time::RuleVersion& out_rule_version); 55 Result GetTimeZoneRuleVersion(Out<Service::PSC::Time::RuleVersion> out_rule_version);
52 Result GetDeviceLocationNameAndUpdatedTime( 56 Result GetDeviceLocationNameAndUpdatedTime(
53 Service::PSC::Time::SteadyClockTimePoint& out_time_point, 57 Out<Service::PSC::Time::LocationName> location_name,
54 Service::PSC::Time::LocationName& location_name); 58 Out<Service::PSC::Time::SteadyClockTimePoint> out_time_point);
55 Result SetDeviceLocationNameWithTimeZoneRule(); 59 Result SetDeviceLocationNameWithTimeZoneRule(Service::PSC::Time::LocationName& location_name,
56 Result GetDeviceLocationNameOperationEventReadableHandle(Kernel::KEvent** out_event); 60 InBuffer<BufferAttr_HipcAutoSelect> binary);
57 Result ToCalendarTime(Service::PSC::Time::CalendarTime& out_calendar_time, 61 Result ParseTimeZoneBinary(OutRule out_rule, InBuffer<BufferAttr_HipcAutoSelect> binary);
58 Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, s64 time, 62 Result GetDeviceLocationNameOperationEventReadableHandle(
59 Tz::Rule& rule); 63 OutCopyHandle<Kernel::KReadableEvent> out_event);
60 Result ToCalendarTimeWithMyRule(Service::PSC::Time::CalendarTime& out_calendar_time, 64 Result ToCalendarTime(Out<Service::PSC::Time::CalendarTime> out_calendar_time,
61 Service::PSC::Time::CalendarAdditionalInfo& out_additional_info, 65 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info,
62 s64 time); 66 s64 time, InRule rule);
63 Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 67 Result ToCalendarTimeWithMyRule(
64 Service::PSC::Time::CalendarTime& calendar_time, Tz::Rule& rule); 68 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
65 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 69 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time);
66 Service::PSC::Time::CalendarTime& calendar_time); 70 Result ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
71 const Service::PSC::Time::CalendarTime& calendar_time, InRule rule);
72 Result ToPosixTimeWithMyRule(Out<u32> out_count,
73 OutArray<s64, BufferAttr_HipcPointer> out_times,
74 const Service::PSC::Time::CalendarTime& calendar_time);
67 75
68private: 76private:
69 void Handle_GetDeviceLocationName(HLERequestContext& ctx);
70 void Handle_SetDeviceLocationName(HLERequestContext& ctx);
71 void Handle_GetTotalLocationNameCount(HLERequestContext& ctx);
72 void Handle_LoadLocationNameList(HLERequestContext& ctx);
73 void Handle_LoadTimeZoneRule(HLERequestContext& ctx);
74 void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx);
75 void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx);
76 void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx);
77 void Handle_ParseTimeZoneBinary(HLERequestContext& ctx);
78 void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx);
79 void Handle_ToCalendarTime(HLERequestContext& ctx);
80 void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx);
81 void Handle_ToPosixTime(HLERequestContext& ctx);
82 void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx);
83
84 Core::System& m_system; 77 Core::System& m_system;
85 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys; 78 std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
86 79
diff --git a/src/core/hle/service/glue/time/time_zone_binary.cpp b/src/core/hle/service/glue/time/time_zone_binary.cpp
index d33f784c0..cc50b6b7b 100644
--- a/src/core/hle/service/glue/time/time_zone_binary.cpp
+++ b/src/core/hle/service/glue/time/time_zone_binary.cpp
@@ -103,7 +103,7 @@ void GetTimeZoneZonePath(std::string& out_path, Service::PSC::Time::LocationName
103 return; 103 return;
104 } 104 }
105 // out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name); 105 // out_path = fmt::format("{}:/zoneinfo/{}", "TimeZoneBinary", name);
106 out_path = fmt::format("/zoneinfo/{}", name.name.data()); 106 out_path = fmt::format("/zoneinfo/{}", name.data());
107} 107}
108 108
109bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) { 109bool IsTimeZoneBinaryValid(Service::PSC::Time::LocationName& name) {
@@ -169,7 +169,7 @@ Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
169} 169}
170 170
171Result GetTimeZoneLocationList(u32& out_count, 171Result GetTimeZoneLocationList(u32& out_count,
172 std::vector<Service::PSC::Time::LocationName>& out_names, 172 std::span<Service::PSC::Time::LocationName> out_names,
173 size_t max_names, u32 index) { 173 size_t max_names, u32 index) {
174 std::string path{}; 174 std::string path{};
175 GetTimeZoneBinaryListPath(path); 175 GetTimeZoneBinaryListPath(path);
@@ -193,7 +193,7 @@ Result GetTimeZoneLocationList(u32& out_count,
193 193
194 if (chr == '\n') { 194 if (chr == '\n') {
195 if (name_count >= index) { 195 if (name_count >= index) {
196 out_names.push_back(current_name); 196 out_names[out_count] = current_name;
197 out_count++; 197 out_count++;
198 if (out_count >= max_names) { 198 if (out_count >= max_names) {
199 break; 199 break;
@@ -209,10 +209,9 @@ Result GetTimeZoneLocationList(u32& out_count,
209 break; 209 break;
210 } 210 }
211 211
212 R_UNLESS(current_name_len <= current_name.name.size() - 2, 212 R_UNLESS(current_name_len <= current_name.size() - 2, Service::PSC::Time::ResultFailed);
213 Service::PSC::Time::ResultFailed);
214 213
215 current_name.name[current_name_len++] = chr; 214 current_name[current_name_len++] = chr;
216 } 215 }
217 216
218 R_SUCCEED(); 217 R_SUCCEED();
diff --git a/src/core/hle/service/glue/time/time_zone_binary.h b/src/core/hle/service/glue/time/time_zone_binary.h
index 2cad6b458..461f4577e 100644
--- a/src/core/hle/service/glue/time/time_zone_binary.h
+++ b/src/core/hle/service/glue/time/time_zone_binary.h
@@ -26,7 +26,7 @@ Result GetTimeZoneVersion(Service::PSC::Time::RuleVersion& out_rule_version);
26Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size, 26Result GetTimeZoneRule(std::span<const u8>& out_rule, size_t& out_rule_size,
27 Service::PSC::Time::LocationName& name); 27 Service::PSC::Time::LocationName& name);
28Result GetTimeZoneLocationList(u32& out_count, 28Result GetTimeZoneLocationList(u32& out_count,
29 std::vector<Service::PSC::Time::LocationName>& out_names, 29 std::span<Service::PSC::Time::LocationName> out_names,
30 size_t max_names, u32 index); 30 size_t max_names, u32 index);
31 31
32} // namespace Service::Glue::Time 32} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/worker.cpp b/src/core/hle/service/glue/time/worker.cpp
index ea0e49b90..f44f3077e 100644
--- a/src/core/hle/service/glue/time/worker.cpp
+++ b/src/core/hle/service/glue/time/worker.cpp
@@ -38,11 +38,12 @@ T GetSettingsItemValue(std::shared_ptr<Service::Set::ISystemSettingsServer>& set
38 38
39TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource, 39TimeWorker::TimeWorker(Core::System& system, StandardSteadyClockResource& steady_clock_resource,
40 FileTimestampWorker& file_timestamp_worker) 40 FileTimestampWorker& file_timestamp_worker)
41 : m_system{system}, m_ctx{m_system, "Glue:58"}, m_event{m_ctx.CreateEvent("Glue:58:Event")}, 41 : m_system{system}, m_ctx{m_system, "Glue:TimeWorker"}, m_event{m_ctx.CreateEvent(
42 "Glue:TimeWorker:Event")},
42 m_steady_clock_resource{steady_clock_resource}, 43 m_steady_clock_resource{steady_clock_resource},
43 m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent( 44 m_file_timestamp_worker{file_timestamp_worker}, m_timer_steady_clock{m_ctx.CreateEvent(
44 "Glue:58:SteadyClockTimerEvent")}, 45 "Glue:TimeWorker:SteadyClockTimerEvent")},
45 m_timer_file_system{m_ctx.CreateEvent("Glue:58:FileTimeTimerEvent")}, 46 m_timer_file_system{m_ctx.CreateEvent("Glue:TimeWorker:FileTimeTimerEvent")},
46 m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} { 47 m_alarm_worker{m_system, m_steady_clock_resource}, m_pm_state_change_handler{m_alarm_worker} {
47 g_ig_report_network_clock_context_set = false; 48 g_ig_report_network_clock_context_set = false;
48 g_report_network_clock_context = {}; 49 g_report_network_clock_context = {};
@@ -113,17 +114,17 @@ void TimeWorker::Initialize(std::shared_ptr<Service::PSC::Time::StaticService> t
113 std::chrono::nanoseconds(fs_notify_time_ns), 114 std::chrono::nanoseconds(fs_notify_time_ns),
114 m_timer_file_system_timing_event); 115 m_timer_file_system_timing_event);
115 116
116 auto res = m_time_sm->GetStandardLocalSystemClock(m_local_clock); 117 auto res = m_time_sm->GetStandardLocalSystemClock(&m_local_clock);
117 ASSERT(res == ResultSuccess); 118 ASSERT(res == ResultSuccess);
118 res = m_time_m->GetStandardLocalClockOperationEvent(&m_local_clock_event); 119 res = m_time_m->GetStandardLocalClockOperationEvent(&m_local_clock_event);
119 ASSERT(res == ResultSuccess); 120 ASSERT(res == ResultSuccess);
120 121
121 res = m_time_sm->GetStandardNetworkSystemClock(m_network_clock); 122 res = m_time_sm->GetStandardNetworkSystemClock(&m_network_clock);
122 ASSERT(res == ResultSuccess); 123 ASSERT(res == ResultSuccess);
123 res = m_time_m->GetStandardNetworkClockOperationEventForServiceManager(&m_network_clock_event); 124 res = m_time_m->GetStandardNetworkClockOperationEventForServiceManager(&m_network_clock_event);
124 ASSERT(res == ResultSuccess); 125 ASSERT(res == ResultSuccess);
125 126
126 res = m_time_sm->GetEphemeralNetworkSystemClock(m_ephemeral_clock); 127 res = m_time_sm->GetEphemeralNetworkSystemClock(&m_ephemeral_clock);
127 ASSERT(res == ResultSuccess); 128 ASSERT(res == ResultSuccess);
128 res = 129 res =
129 m_time_m->GetEphemeralNetworkClockOperationEventForServiceManager(&m_ephemeral_clock_event); 130 m_time_m->GetEphemeralNetworkClockOperationEventForServiceManager(&m_ephemeral_clock_event);
@@ -183,22 +184,19 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
183 AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); 184 AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
184 // TODO 185 // TODO
185 // AddWaiter(gIPmModuleService::GetEvent(), 1); 186 // AddWaiter(gIPmModuleService::GetEvent(), 1);
186 AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange); 187 AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange);
187 } else { 188 } else {
188 AddWaiter(&m_event->GetReadableEvent(), EventType::Exit); 189 AddWaiter(&m_event->GetReadableEvent(), EventType::Exit);
189 // TODO 190 // TODO
190 // AddWaiter(gIPmModuleService::GetEvent(), 1); 191 // AddWaiter(gIPmModuleService::GetEvent(), 1);
191 AddWaiter(&m_alarm_worker.GetEvent().GetReadableEvent(), EventType::PowerStateChange); 192 AddWaiter(&m_alarm_worker.GetEvent(), EventType::PowerStateChange);
192 AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms); 193 AddWaiter(&m_alarm_worker.GetTimerEvent().GetReadableEvent(), EventType::SignalAlarms);
193 AddWaiter(&m_local_clock_event->GetReadableEvent(), EventType::UpdateLocalSystemClock); 194 AddWaiter(m_local_clock_event, EventType::UpdateLocalSystemClock);
194 AddWaiter(&m_network_clock_event->GetReadableEvent(), 195 AddWaiter(m_network_clock_event, EventType::UpdateNetworkSystemClock);
195 EventType::UpdateNetworkSystemClock); 196 AddWaiter(m_ephemeral_clock_event, EventType::UpdateEphemeralSystemClock);
196 AddWaiter(&m_ephemeral_clock_event->GetReadableEvent(),
197 EventType::UpdateEphemeralSystemClock);
198 AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock); 197 AddWaiter(&m_timer_steady_clock->GetReadableEvent(), EventType::UpdateSteadyClock);
199 AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp); 198 AddWaiter(&m_timer_file_system->GetReadableEvent(), EventType::UpdateFileTimestamp);
200 AddWaiter(&m_standard_user_auto_correct_clock_event->GetReadableEvent(), 199 AddWaiter(m_standard_user_auto_correct_clock_event, EventType::AutoCorrect);
201 EventType::AutoCorrect);
202 } 200 }
203 201
204 s32 out_index{-1}; 202 s32 out_index{-1};
@@ -237,7 +235,7 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
237 m_local_clock_event->Clear(); 235 m_local_clock_event->Clear();
238 236
239 Service::PSC::Time::SystemClockContext context{}; 237 Service::PSC::Time::SystemClockContext context{};
240 auto res = m_local_clock->GetSystemClockContext(context); 238 auto res = m_local_clock->GetSystemClockContext(&context);
241 ASSERT(res == ResultSuccess); 239 ASSERT(res == ResultSuccess);
242 240
243 m_set_sys->SetUserSystemClockContext(context); 241 m_set_sys->SetUserSystemClockContext(context);
@@ -248,12 +246,12 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
248 case EventType::UpdateNetworkSystemClock: { 246 case EventType::UpdateNetworkSystemClock: {
249 m_network_clock_event->Clear(); 247 m_network_clock_event->Clear();
250 Service::PSC::Time::SystemClockContext context{}; 248 Service::PSC::Time::SystemClockContext context{};
251 auto res = m_network_clock->GetSystemClockContext(context); 249 auto res = m_network_clock->GetSystemClockContext(&context);
252 ASSERT(res == ResultSuccess); 250 ASSERT(res == ResultSuccess);
253 m_set_sys->SetNetworkSystemClockContext(context); 251 m_set_sys->SetNetworkSystemClockContext(context);
254 252
255 s64 time{}; 253 s64 time{};
256 if (m_network_clock->GetCurrentTime(time) != ResultSuccess) { 254 if (m_network_clock->GetCurrentTime(&time) != ResultSuccess) {
257 break; 255 break;
258 } 256 }
259 257
@@ -275,13 +273,13 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
275 m_ephemeral_clock_event->Clear(); 273 m_ephemeral_clock_event->Clear();
276 274
277 Service::PSC::Time::SystemClockContext context{}; 275 Service::PSC::Time::SystemClockContext context{};
278 auto res = m_ephemeral_clock->GetSystemClockContext(context); 276 auto res = m_ephemeral_clock->GetSystemClockContext(&context);
279 if (res != ResultSuccess) { 277 if (res != ResultSuccess) {
280 break; 278 break;
281 } 279 }
282 280
283 s64 time{}; 281 s64 time{};
284 res = m_ephemeral_clock->GetCurrentTime(time); 282 res = m_ephemeral_clock->GetCurrentTime(&time);
285 if (res != ResultSuccess) { 283 if (res != ResultSuccess) {
286 break; 284 break;
287 } 285 }
@@ -317,11 +315,11 @@ void TimeWorker::ThreadFunc(std::stop_token stop_token) {
317 315
318 bool automatic_correction{}; 316 bool automatic_correction{};
319 auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled( 317 auto res = m_time_sm->IsStandardUserSystemClockAutomaticCorrectionEnabled(
320 automatic_correction); 318 &automatic_correction);
321 ASSERT(res == ResultSuccess); 319 ASSERT(res == ResultSuccess);
322 320
323 Service::PSC::Time::SteadyClockTimePoint time_point{}; 321 Service::PSC::Time::SteadyClockTimePoint time_point{};
324 res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); 322 res = m_time_sm->GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(&time_point);
325 ASSERT(res == ResultSuccess); 323 ASSERT(res == ResultSuccess);
326 324
327 m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction); 325 m_set_sys->SetUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
diff --git a/src/core/hle/service/glue/time/worker.h b/src/core/hle/service/glue/time/worker.h
index adbbe6b6d..75e5c4d0f 100644
--- a/src/core/hle/service/glue/time/worker.h
+++ b/src/core/hle/service/glue/time/worker.h
@@ -49,10 +49,10 @@ private:
49 std::shared_ptr<Service::PSC::Time::SystemClock> m_ephemeral_clock; 49 std::shared_ptr<Service::PSC::Time::SystemClock> m_ephemeral_clock;
50 StandardSteadyClockResource& m_steady_clock_resource; 50 StandardSteadyClockResource& m_steady_clock_resource;
51 FileTimestampWorker& m_file_timestamp_worker; 51 FileTimestampWorker& m_file_timestamp_worker;
52 Kernel::KEvent* m_local_clock_event{}; 52 Kernel::KReadableEvent* m_local_clock_event{};
53 Kernel::KEvent* m_network_clock_event{}; 53 Kernel::KReadableEvent* m_network_clock_event{};
54 Kernel::KEvent* m_ephemeral_clock_event{}; 54 Kernel::KReadableEvent* m_ephemeral_clock_event{};
55 Kernel::KEvent* m_standard_user_auto_correct_clock_event{}; 55 Kernel::KReadableEvent* m_standard_user_auto_correct_clock_event{};
56 Kernel::KEvent* m_timer_steady_clock{}; 56 Kernel::KEvent* m_timer_steady_clock{};
57 std::shared_ptr<Core::Timing::EventType> m_timer_steady_clock_timing_event; 57 std::shared_ptr<Core::Timing::EventType> m_timer_steady_clock_timing_event;
58 Kernel::KEvent* m_timer_file_system{}; 58 Kernel::KEvent* m_timer_file_system{};
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index 9ffe027ff..3603d8ccf 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -8,6 +8,7 @@
8#include "core/hle/kernel/k_shared_memory.h" 8#include "core/hle/kernel/k_shared_memory.h"
9#include "core/hle/kernel/k_transfer_memory.h" 9#include "core/hle/kernel/k_transfer_memory.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/service/cmif_serialization.h"
11#include "core/hle/service/hid/hid_server.h" 12#include "core/hle/service/hid/hid_server.h"
12#include "core/hle/service/ipc_helpers.h" 13#include "core/hle/service/ipc_helpers.h"
13#include "core/memory.h" 14#include "core/memory.h"
@@ -153,7 +154,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
153 {104, &IHidServer::DeactivateNpad, "DeactivateNpad"}, 154 {104, &IHidServer::DeactivateNpad, "DeactivateNpad"},
154 {106, &IHidServer::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, 155 {106, &IHidServer::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
155 {107, &IHidServer::DisconnectNpad, "DisconnectNpad"}, 156 {107, &IHidServer::DisconnectNpad, "DisconnectNpad"},
156 {108, &IHidServer::GetPlayerLedPattern, "GetPlayerLedPattern"}, 157 {108, C<&IHidServer::GetPlayerLedPattern>, "GetPlayerLedPattern"},
157 {109, &IHidServer::ActivateNpadWithRevision, "ActivateNpadWithRevision"}, 158 {109, &IHidServer::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
158 {120, &IHidServer::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, 159 {120, &IHidServer::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
159 {121, &IHidServer::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, 160 {121, &IHidServer::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
@@ -1135,19 +1136,39 @@ void IHidServer::DisconnectNpad(HLERequestContext& ctx) {
1135 rb.Push(ResultSuccess); 1136 rb.Push(ResultSuccess);
1136} 1137}
1137 1138
1138void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) { 1139Result IHidServer::GetPlayerLedPattern(Out<Core::HID::LedPattern> out_led_pattern,
1139 IPC::RequestParser rp{ctx}; 1140 Core::HID::NpadIdType npad_id) {
1140 const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
1141
1142 Core::HID::LedPattern pattern{0, 0, 0, 0};
1143 auto controller = GetResourceManager()->GetNpad();
1144 const auto result = controller->GetLedPattern(npad_id, pattern);
1145
1146 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); 1141 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
1147 1142
1148 IPC::ResponseBuilder rb{ctx, 4}; 1143 switch (npad_id) {
1149 rb.Push(result); 1144 case Core::HID::NpadIdType::Player1:
1150 rb.Push(pattern.raw); 1145 *out_led_pattern = Core::HID::LedPattern{1, 0, 0, 0};
1146 R_SUCCEED();
1147 case Core::HID::NpadIdType::Player2:
1148 *out_led_pattern = Core::HID::LedPattern{1, 1, 0, 0};
1149 R_SUCCEED();
1150 case Core::HID::NpadIdType::Player3:
1151 *out_led_pattern = Core::HID::LedPattern{1, 1, 1, 0};
1152 R_SUCCEED();
1153 case Core::HID::NpadIdType::Player4:
1154 *out_led_pattern = Core::HID::LedPattern{1, 1, 1, 1};
1155 R_SUCCEED();
1156 case Core::HID::NpadIdType::Player5:
1157 *out_led_pattern = Core::HID::LedPattern{1, 0, 0, 1};
1158 R_SUCCEED();
1159 case Core::HID::NpadIdType::Player6:
1160 *out_led_pattern = Core::HID::LedPattern{1, 0, 1, 0};
1161 R_SUCCEED();
1162 case Core::HID::NpadIdType::Player7:
1163 *out_led_pattern = Core::HID::LedPattern{1, 0, 1, 1};
1164 R_SUCCEED();
1165 case Core::HID::NpadIdType::Player8:
1166 *out_led_pattern = Core::HID::LedPattern{0, 1, 1, 0};
1167 R_SUCCEED();
1168 default:
1169 *out_led_pattern = Core::HID::LedPattern{0, 0, 0, 0};
1170 R_SUCCEED();
1171 }
1151} 1172}
1152 1173
1153void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { 1174void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
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 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8#include "hid_core/hid_types.h"
7 9
8namespace Core { 10namespace Core {
9class System; 11class System;
@@ -66,7 +68,8 @@ private:
66 void DeactivateNpad(HLERequestContext& ctx); 68 void DeactivateNpad(HLERequestContext& ctx);
67 void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx); 69 void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
68 void DisconnectNpad(HLERequestContext& ctx); 70 void DisconnectNpad(HLERequestContext& ctx);
69 void GetPlayerLedPattern(HLERequestContext& ctx); 71 Result GetPlayerLedPattern(Out<Core::HID::LedPattern> out_led_pattern,
72 Core::HID::NpadIdType npad_id);
70 void ActivateNpadWithRevision(HLERequestContext& ctx); 73 void ActivateNpadWithRevision(HLERequestContext& ctx);
71 void SetNpadJoyHoldType(HLERequestContext& ctx); 74 void SetNpadJoyHoldType(HLERequestContext& ctx);
72 void GetNpadJoyHoldType(HLERequestContext& ctx); 75 void GetNpadJoyHoldType(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:
111 R_RETURN(result); 111 R_RETURN(result);
112 } 112 }
113 113
114 Result UpdateLatest(Out<CharInfo> out_char_info, CharInfo& char_info, SourceFlag source_flag) { 114 Result UpdateLatest(Out<CharInfo> out_char_info, const CharInfo& char_info,
115 SourceFlag source_flag) {
115 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); 116 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
116 117
117 R_RETURN(manager->UpdateLatest(metadata, *out_char_info, char_info, source_flag)); 118 R_RETURN(manager->UpdateLatest(metadata, *out_char_info, char_info, source_flag));
@@ -159,7 +160,7 @@ private:
159 R_RETURN(result); 160 R_RETURN(result);
160 } 161 }
161 162
162 Result UpdateLatest1(Out<StoreData> out_store_data, StoreData& store_data, 163 Result UpdateLatest1(Out<StoreData> out_store_data, const StoreData& store_data,
163 SourceFlag source_flag) { 164 SourceFlag source_flag) {
164 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag); 165 LOG_INFO(Service_Mii, "called with source_flag={}", source_flag);
165 R_UNLESS(is_system, ResultPermissionDenied); 166 R_UNLESS(is_system, ResultPermissionDenied);
@@ -243,7 +244,7 @@ private:
243 R_SUCCEED(); 244 R_SUCCEED();
244 } 245 }
245 246
246 Result GetIndex(Out<s32> out_index, CharInfo& char_info) { 247 Result GetIndex(Out<s32> out_index, const CharInfo& char_info) {
247 LOG_DEBUG(Service_Mii, "called"); 248 LOG_DEBUG(Service_Mii, "called");
248 249
249 R_RETURN(manager->GetIndex(metadata, char_info, *out_index)); 250 R_RETURN(manager->GetIndex(metadata, char_info, *out_index));
@@ -257,25 +258,25 @@ private:
257 R_SUCCEED(); 258 R_SUCCEED();
258 } 259 }
259 260
260 Result Convert(Out<CharInfo> out_char_info, Ver3StoreData& mii_v3) { 261 Result Convert(Out<CharInfo> out_char_info, const Ver3StoreData& mii_v3) {
261 LOG_INFO(Service_Mii, "called"); 262 LOG_INFO(Service_Mii, "called");
262 263
263 R_RETURN(manager->ConvertV3ToCharInfo(*out_char_info, mii_v3)); 264 R_RETURN(manager->ConvertV3ToCharInfo(*out_char_info, mii_v3));
264 } 265 }
265 266
266 Result ConvertCoreDataToCharInfo(Out<CharInfo> out_char_info, CoreData& core_data) { 267 Result ConvertCoreDataToCharInfo(Out<CharInfo> out_char_info, const CoreData& core_data) {
267 LOG_INFO(Service_Mii, "called"); 268 LOG_INFO(Service_Mii, "called");
268 269
269 R_RETURN(manager->ConvertCoreDataToCharInfo(*out_char_info, core_data)); 270 R_RETURN(manager->ConvertCoreDataToCharInfo(*out_char_info, core_data));
270 } 271 }
271 272
272 Result ConvertCharInfoToCoreData(Out<CoreData> out_core_data, CharInfo& char_info) { 273 Result ConvertCharInfoToCoreData(Out<CoreData> out_core_data, const CharInfo& char_info) {
273 LOG_INFO(Service_Mii, "called"); 274 LOG_INFO(Service_Mii, "called");
274 275
275 R_RETURN(manager->ConvertCharInfoToCoreData(*out_core_data, char_info)); 276 R_RETURN(manager->ConvertCharInfoToCoreData(*out_core_data, char_info));
276 } 277 }
277 278
278 Result Append(CharInfo& char_info) { 279 Result Append(const CharInfo& char_info) {
279 LOG_INFO(Service_Mii, "called"); 280 LOG_INFO(Service_Mii, "called");
280 281
281 R_RETURN(manager->Append(metadata, char_info)); 282 R_RETURN(manager->Append(metadata, char_info));
diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp
index 1e2d2d212..28e3000bd 100644
--- a/src/core/hle/service/nfc/common/device.cpp
+++ b/src/core/hle/service/nfc/common/device.cpp
@@ -1405,7 +1405,7 @@ NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
1405 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); 1405 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
1406 1406
1407 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{}; 1407 std::shared_ptr<Service::Glue::Time::TimeZoneService> timezone_service{};
1408 static_service->GetTimeZoneService(timezone_service); 1408 static_service->GetTimeZoneService(&timezone_service);
1409 1409
1410 Service::PSC::Time::CalendarTime calendar_time{}; 1410 Service::PSC::Time::CalendarTime calendar_time{};
1411 Service::PSC::Time::CalendarAdditionalInfo additional_info{}; 1411 Service::PSC::Time::CalendarAdditionalInfo additional_info{};
@@ -1416,7 +1416,7 @@ NFP::AmiiboDate NfcDevice::GetAmiiboDate(s64 posix_time) const {
1416 amiibo_date.SetMonth(1); 1416 amiibo_date.SetMonth(1);
1417 amiibo_date.SetDay(1); 1417 amiibo_date.SetDay(1);
1418 1418
1419 if (timezone_service->ToCalendarTimeWithMyRule(calendar_time, additional_info, posix_time) == 1419 if (timezone_service->ToCalendarTimeWithMyRule(&calendar_time, &additional_info, posix_time) ==
1420 ResultSuccess) { 1420 ResultSuccess) {
1421 amiibo_date.SetYear(calendar_time.year); 1421 amiibo_date.SetYear(calendar_time.year);
1422 amiibo_date.SetMonth(calendar_time.month); 1422 amiibo_date.SetMonth(calendar_time.month);
@@ -1431,10 +1431,10 @@ s64 NfcDevice::GetCurrentPosixTime() const {
1431 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); 1431 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
1432 1432
1433 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; 1433 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
1434 static_service->GetStandardSteadyClock(steady_clock); 1434 static_service->GetStandardSteadyClock(&steady_clock);
1435 1435
1436 Service::PSC::Time::SteadyClockTimePoint time_point{}; 1436 Service::PSC::Time::SteadyClockTimePoint time_point{};
1437 R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); 1437 R_ASSERT(steady_clock->GetCurrentTimePoint(&time_point));
1438 return time_point.time_point; 1438 return time_point.time_point;
1439} 1439}
1440 1440
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
index b60699c45..94a8243b5 100644
--- a/src/core/hle/service/nfc/common/device_manager.cpp
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -91,10 +91,10 @@ Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max
91 true); 91 true);
92 92
93 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; 93 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
94 static_service->GetStandardSteadyClock(steady_clock); 94 static_service->GetStandardSteadyClock(&steady_clock);
95 95
96 Service::PSC::Time::SteadyClockTimePoint time_point{}; 96 Service::PSC::Time::SteadyClockTimePoint time_point{};
97 R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); 97 R_ASSERT(steady_clock->GetCurrentTimePoint(&time_point));
98 98
99 const s64 elapsed_time = time_point.time_point - time_since_last_error; 99 const s64 elapsed_time = time_point.time_point - time_since_last_error;
100 if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) { 100 if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) {
@@ -754,10 +754,10 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
754 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true); 754 system.ServiceManager().GetService<Service::Glue::Time::StaticService>("time:u", true);
755 755
756 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{}; 756 std::shared_ptr<Service::PSC::Time::SteadyClock> steady_clock{};
757 static_service->GetStandardSteadyClock(steady_clock); 757 static_service->GetStandardSteadyClock(&steady_clock);
758 758
759 Service::PSC::Time::SteadyClockTimePoint time_point{}; 759 Service::PSC::Time::SteadyClockTimePoint time_point{};
760 R_ASSERT(steady_clock->GetCurrentTimePoint(time_point)); 760 R_ASSERT(steady_clock->GetCurrentTimePoint(&time_point));
761 761
762 time_since_last_error = time_point.time_point; 762 time_since_last_error = time_point.time_point;
763 } 763 }
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:
185 {3, &IRequest::Cancel, "Cancel"}, 185 {3, &IRequest::Cancel, "Cancel"},
186 {4, &IRequest::Submit, "Submit"}, 186 {4, &IRequest::Submit, "Submit"},
187 {5, nullptr, "SetRequirement"}, 187 {5, nullptr, "SetRequirement"},
188 {6, nullptr, "SetRequirementPreset"}, 188 {6, &IRequest::SetRequirementPreset, "SetRequirementPreset"},
189 {8, nullptr, "SetPriority"}, 189 {8, nullptr, "SetPriority"},
190 {9, nullptr, "SetNetworkProfileId"}, 190 {9, nullptr, "SetNetworkProfileId"},
191 {10, nullptr, "SetRejectable"}, 191 {10, nullptr, "SetRejectable"},
@@ -237,6 +237,16 @@ private:
237 rb.PushEnum(state); 237 rb.PushEnum(state);
238 } 238 }
239 239
240 void SetRequirementPreset(HLERequestContext& ctx) {
241 IPC::RequestParser rp{ctx};
242 const auto param_1 = rp.Pop<u32>();
243
244 LOG_WARNING(Service_NIFM, "(STUBBED) called, param_1={}", param_1);
245
246 IPC::ResponseBuilder rb{ctx, 2};
247 rb.Push(ResultSuccess);
248 }
249
240 void GetResult(HLERequestContext& ctx) { 250 void GetResult(HLERequestContext& ctx) {
241 LOG_DEBUG(Service_NIFM, "(STUBBED) called"); 251 LOG_DEBUG(Service_NIFM, "(STUBBED) called");
242 252
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 @@
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "common/settings.h" 5#include "common/settings.h"
6#include "core/arm/debug.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/file_sys/control_metadata.h" 8#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/patch_manager.h" 9#include "core/file_sys/patch_manager.h"
@@ -544,8 +545,8 @@ IDocumentInterface::IDocumentInterface(Core::System& system_)
544 // clang-format off 545 // clang-format off
545 static const FunctionInfo functions[] = { 546 static const FunctionInfo functions[] = {
546 {21, nullptr, "GetApplicationContentPath"}, 547 {21, nullptr, "GetApplicationContentPath"},
547 {23, nullptr, "ResolveApplicationContentPath"}, 548 {23, &IDocumentInterface::ResolveApplicationContentPath, "ResolveApplicationContentPath"},
548 {93, nullptr, "GetRunningApplicationProgramId"}, 549 {92, &IDocumentInterface::GetRunningApplicationProgramId, "GetRunningApplicationProgramId"},
549 }; 550 };
550 // clang-format on 551 // clang-format on
551 552
@@ -554,6 +555,32 @@ IDocumentInterface::IDocumentInterface(Core::System& system_)
554 555
555IDocumentInterface::~IDocumentInterface() = default; 556IDocumentInterface::~IDocumentInterface() = default;
556 557
558void IDocumentInterface::ResolveApplicationContentPath(HLERequestContext& ctx) {
559 struct ContentPath {
560 u8 file_system_proxy_type;
561 u64 program_id;
562 };
563 static_assert(sizeof(ContentPath) == 0x10, "ContentPath has wrong size");
564
565 IPC::RequestParser rp{ctx};
566 auto content_path = rp.PopRaw<ContentPath>();
567 LOG_WARNING(Service_NS, "(STUBBED) called, file_system_proxy_type={}, program_id={:016X}",
568 content_path.file_system_proxy_type, content_path.program_id);
569
570 IPC::ResponseBuilder rb{ctx, 2};
571 rb.Push(ResultSuccess);
572}
573
574void IDocumentInterface::GetRunningApplicationProgramId(HLERequestContext& ctx) {
575 IPC::RequestParser rp{ctx};
576 const auto caller_program_id = rp.PopRaw<u64>();
577 LOG_WARNING(Service_NS, "(STUBBED) called, caller_program_id={:016X}", caller_program_id);
578
579 IPC::ResponseBuilder rb{ctx, 4};
580 rb.Push(ResultSuccess);
581 rb.Push<u64>(system.GetApplicationProcessProgramID());
582}
583
557IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_) 584IDownloadTaskInterface::IDownloadTaskInterface(Core::System& system_)
558 : ServiceFramework{system_, "IDownloadTaskInterface"} { 585 : ServiceFramework{system_, "IDownloadTaskInterface"} {
559 // clang-format off 586 // clang-format off
@@ -613,6 +640,40 @@ IFactoryResetInterface::IFactoryResetInterface(Core::System& system_)
613 640
614IFactoryResetInterface::~IFactoryResetInterface() = default; 641IFactoryResetInterface::~IFactoryResetInterface() = default;
615 642
643IReadOnlyApplicationRecordInterface::IReadOnlyApplicationRecordInterface(Core::System& system_)
644 : ServiceFramework{system_, "IReadOnlyApplicationRecordInterface"} {
645 static const FunctionInfo functions[] = {
646 {0, &IReadOnlyApplicationRecordInterface::HasApplicationRecord, "HasApplicationRecord"},
647 {1, nullptr, "NotifyApplicationFailure"},
648 {2, &IReadOnlyApplicationRecordInterface::IsDataCorruptedResult, "IsDataCorruptedResult"},
649 };
650 // clang-format on
651
652 RegisterHandlers(functions);
653}
654
655IReadOnlyApplicationRecordInterface::~IReadOnlyApplicationRecordInterface() = default;
656
657void IReadOnlyApplicationRecordInterface::HasApplicationRecord(HLERequestContext& ctx) {
658 IPC::RequestParser rp{ctx};
659 const u64 program_id = rp.PopRaw<u64>();
660 LOG_WARNING(Service_NS, "(STUBBED) called, program_id={:X}", program_id);
661
662 IPC::ResponseBuilder rb{ctx, 3};
663 rb.Push(ResultSuccess);
664 rb.Push<u8>(1);
665}
666
667void IReadOnlyApplicationRecordInterface::IsDataCorruptedResult(HLERequestContext& ctx) {
668 IPC::RequestParser rp{ctx};
669 const auto result = rp.PopRaw<Result>();
670 LOG_WARNING(Service_NS, "(STUBBED) called, result={:#x}", result.GetInnerValue());
671
672 IPC::ResponseBuilder rb{ctx, 3};
673 rb.Push(ResultSuccess);
674 rb.Push<u8>(0);
675}
676
616IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface( 677IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
617 Core::System& system_) 678 Core::System& system_)
618 : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} { 679 : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
@@ -663,7 +724,7 @@ NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name
663 static const FunctionInfo functions[] = { 724 static const FunctionInfo functions[] = {
664 {7988, nullptr, "GetDynamicRightsInterface"}, 725 {7988, nullptr, "GetDynamicRightsInterface"},
665 {7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"}, 726 {7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"},
666 {7991, nullptr, "GetReadOnlyApplicationRecordInterface"}, 727 {7991, &NS::PushInterface<IReadOnlyApplicationRecordInterface>, "GetReadOnlyApplicationRecordInterface"},
667 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"}, 728 {7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
668 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"}, 729 {7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
669 {7994, &NS::PushInterface<IFactoryResetInterface>, "GetFactoryResetInterface"}, 730 {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> {
58public: 58public:
59 explicit IDocumentInterface(Core::System& system_); 59 explicit IDocumentInterface(Core::System& system_);
60 ~IDocumentInterface() override; 60 ~IDocumentInterface() override;
61
62private:
63 void ResolveApplicationContentPath(HLERequestContext& ctx);
64 void GetRunningApplicationProgramId(HLERequestContext& ctx);
61}; 65};
62 66
63class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> { 67class IDownloadTaskInterface final : public ServiceFramework<IDownloadTaskInterface> {
@@ -78,6 +82,17 @@ public:
78 ~IFactoryResetInterface() override; 82 ~IFactoryResetInterface() override;
79}; 83};
80 84
85class IReadOnlyApplicationRecordInterface final
86 : public ServiceFramework<IReadOnlyApplicationRecordInterface> {
87public:
88 explicit IReadOnlyApplicationRecordInterface(Core::System& system_);
89 ~IReadOnlyApplicationRecordInterface() override;
90
91private:
92 void HasApplicationRecord(HLERequestContext& ctx);
93 void IsDataCorruptedResult(HLERequestContext& ctx);
94};
95
81class IReadOnlyApplicationControlDataInterface final 96class IReadOnlyApplicationControlDataInterface final
82 : public ServiceFramework<IReadOnlyApplicationControlDataInterface> { 97 : public ServiceFramework<IReadOnlyApplicationControlDataInterface> {
83public: 98public:
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) {
83 83
84 // Check if this memory block is heap. 84 // Check if this memory block is heap.
85 if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { 85 if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) {
86 if (svc_mem_info.size > region_size) { 86 if (region_start + region_size == svc_mem_info.base_address) {
87 region_size += svc_mem_info.size;
88 } else if (svc_mem_info.size > region_size) {
87 region_size = svc_mem_info.size; 89 region_size = svc_mem_info.size;
88 region_start = svc_mem_info.base_address; 90 region_start = svc_mem_info.base_address;
89 } 91 }
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
index 86e272b41..e71652cdf 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -128,7 +128,7 @@ Result AllocateHandleForBuffer(u32* out_handle, Nvidia::Module& nvdrv, Nvidia::D
128 128
129 // Ensure we maintain a clean state on failure. 129 // Ensure we maintain a clean state on failure.
130 ON_RESULT_FAILURE { 130 ON_RESULT_FAILURE {
131 ASSERT(R_SUCCEEDED(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd))); 131 R_ASSERT(FreeNvMapHandle(*nvmap, *out_handle, nvmap_fd));
132 }; 132 };
133 133
134 // Assign the allocated memory to the handle. 134 // Assign the allocated memory to the handle.
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp
index 71d6fdb0c..51133853c 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.cpp
+++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp
@@ -198,6 +198,16 @@ bool Nvnflinger::CloseLayer(u64 layer_id) {
198 return false; 198 return false;
199} 199}
200 200
201void Nvnflinger::SetLayerVisibility(u64 layer_id, bool visible) {
202 const auto lock_guard = Lock();
203
204 for (auto& display : displays) {
205 if (auto* layer = display.FindLayer(layer_id); layer) {
206 layer->SetVisibility(visible);
207 }
208 }
209}
210
201void Nvnflinger::DestroyLayer(u64 layer_id) { 211void Nvnflinger::DestroyLayer(u64 layer_id) {
202 const auto lock_guard = Lock(); 212 const auto lock_guard = Lock();
203 213
diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h
index a60e0ae6b..369439142 100644
--- a/src/core/hle/service/nvnflinger/nvnflinger.h
+++ b/src/core/hle/service/nvnflinger/nvnflinger.h
@@ -79,6 +79,9 @@ public:
79 /// Closes a layer on all displays for the given layer ID. 79 /// Closes a layer on all displays for the given layer ID.
80 bool CloseLayer(u64 layer_id); 80 bool CloseLayer(u64 layer_id);
81 81
82 /// Makes a layer visible on all displays for the given layer ID.
83 void SetLayerVisibility(u64 layer_id, bool visible);
84
82 /// Destroys the given layer ID. 85 /// Destroys the given layer ID.
83 void DestroyLayer(u64 layer_id); 86 void DestroyLayer(u64 layer_id);
84 87
diff --git a/src/core/hle/service/psc/time/common.h b/src/core/hle/service/psc/time/common.h
index d17b31143..3e13144a0 100644
--- a/src/core/hle/service/psc/time/common.h
+++ b/src/core/hle/service/psc/time/common.h
@@ -5,6 +5,7 @@
5 5
6#include <array> 6#include <array>
7#include <chrono> 7#include <chrono>
8#include <fmt/format.h>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "common/intrusive_list.h" 11#include "common/intrusive_list.h"
@@ -21,8 +22,14 @@ class System;
21namespace Service::PSC::Time { 22namespace Service::PSC::Time {
22using ClockSourceId = Common::UUID; 23using ClockSourceId = Common::UUID;
23 24
25enum class TimeType : u8 {
26 UserSystemClock = 0,
27 NetworkSystemClock = 1,
28 LocalSystemClock = 2,
29};
30
24struct SteadyClockTimePoint { 31struct SteadyClockTimePoint {
25 constexpr bool IdMatches(SteadyClockTimePoint& other) { 32 constexpr bool IdMatches(const SteadyClockTimePoint& other) const {
26 return clock_source_id == other.clock_source_id; 33 return clock_source_id == other.clock_source_id;
27 } 34 }
28 bool operator==(const SteadyClockTimePoint& other) const = default; 35 bool operator==(const SteadyClockTimePoint& other) const = default;
@@ -42,12 +49,6 @@ struct SystemClockContext {
42static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext has the wrong size!"); 49static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext has the wrong size!");
43static_assert(std::is_trivial_v<SystemClockContext>); 50static_assert(std::is_trivial_v<SystemClockContext>);
44 51
45enum class TimeType : u8 {
46 UserSystemClock,
47 NetworkSystemClock,
48 LocalSystemClock,
49};
50
51struct CalendarTime { 52struct CalendarTime {
52 s16 year; 53 s16 year;
53 s8 month; 54 s8 month;
@@ -67,14 +68,10 @@ struct CalendarAdditionalInfo {
67}; 68};
68static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo has the wrong size!"); 69static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo has the wrong size!");
69 70
70struct LocationName { 71using LocationName = std::array<char, 0x24>;
71 std::array<char, 36> name;
72};
73static_assert(sizeof(LocationName) == 0x24, "LocationName has the wrong size!"); 72static_assert(sizeof(LocationName) == 0x24, "LocationName has the wrong size!");
74 73
75struct RuleVersion { 74using RuleVersion = std::array<char, 0x10>;
76 std::array<char, 16> version;
77};
78static_assert(sizeof(RuleVersion) == 0x10, "RuleVersion has the wrong size!"); 75static_assert(sizeof(RuleVersion) == 0x10, "RuleVersion has the wrong size!");
79 76
80struct ClockSnapshot { 77struct ClockSnapshot {
@@ -152,8 +149,8 @@ constexpr inline std::chrono::nanoseconds ConvertToTimeSpan(s64 ticks) {
152 return std::chrono::nanoseconds(a + b); 149 return std::chrono::nanoseconds(a + b);
153} 150}
154 151
155constexpr inline Result GetSpanBetweenTimePoints(s64* out_seconds, SteadyClockTimePoint& a, 152constexpr inline Result GetSpanBetweenTimePoints(s64* out_seconds, const SteadyClockTimePoint& a,
156 SteadyClockTimePoint& b) { 153 const SteadyClockTimePoint& b) {
157 R_UNLESS(out_seconds, ResultInvalidArgument); 154 R_UNLESS(out_seconds, ResultInvalidArgument);
158 R_UNLESS(a.IdMatches(b), ResultInvalidArgument); 155 R_UNLESS(a.IdMatches(b), ResultInvalidArgument);
159 R_UNLESS(a.time_point >= 0 || b.time_point <= a.time_point + std::numeric_limits<s64>::max(), 156 R_UNLESS(a.time_point >= 0 || b.time_point <= a.time_point + std::numeric_limits<s64>::max(),
@@ -166,3 +163,111 @@ constexpr inline Result GetSpanBetweenTimePoints(s64* out_seconds, SteadyClockTi
166} 163}
167 164
168} // namespace Service::PSC::Time 165} // namespace Service::PSC::Time
166
167template <>
168struct fmt::formatter<Service::PSC::Time::TimeType> : fmt::formatter<fmt::string_view> {
169 template <typename FormatContext>
170 auto format(Service::PSC::Time::TimeType type, FormatContext& ctx) {
171 const string_view name = [type] {
172 using Service::PSC::Time::TimeType;
173 switch (type) {
174 case TimeType::UserSystemClock:
175 return "UserSystemClock";
176 case TimeType::NetworkSystemClock:
177 return "NetworkSystemClock";
178 case TimeType::LocalSystemClock:
179 return "LocalSystemClock";
180 }
181 return "Invalid";
182 }();
183 return formatter<string_view>::format(name, ctx);
184 }
185};
186
187template <>
188struct fmt::formatter<Service::PSC::Time::SteadyClockTimePoint> : fmt::formatter<fmt::string_view> {
189 template <typename FormatContext>
190 auto format(const Service::PSC::Time::SteadyClockTimePoint& time_point,
191 FormatContext& ctx) const {
192 return fmt::format_to(ctx.out(), "[time_point={}]", time_point.time_point);
193 }
194};
195
196template <>
197struct fmt::formatter<Service::PSC::Time::SystemClockContext> : fmt::formatter<fmt::string_view> {
198 template <typename FormatContext>
199 auto format(const Service::PSC::Time::SystemClockContext& context, FormatContext& ctx) const {
200 return fmt::format_to(ctx.out(), "[offset={} steady_time_point={}]", context.offset,
201 context.steady_time_point.time_point);
202 }
203};
204
205template <>
206struct fmt::formatter<Service::PSC::Time::CalendarTime> : fmt::formatter<fmt::string_view> {
207 template <typename FormatContext>
208 auto format(const Service::PSC::Time::CalendarTime& calendar, FormatContext& ctx) const {
209 return fmt::format_to(ctx.out(), "[{:02}/{:02}/{:04} {:02}:{:02}:{:02}]", calendar.day,
210 calendar.month, calendar.year, calendar.hour, calendar.minute,
211 calendar.second);
212 }
213};
214
215template <>
216struct fmt::formatter<Service::PSC::Time::CalendarAdditionalInfo>
217 : fmt::formatter<fmt::string_view> {
218 template <typename FormatContext>
219 auto format(const Service::PSC::Time::CalendarAdditionalInfo& additional,
220 FormatContext& ctx) const {
221 return fmt::format_to(ctx.out(), "[weekday={} yearday={} name={} is_dst={} ut_offset={}]",
222 additional.day_of_week, additional.day_of_year,
223 additional.name.data(), additional.is_dst, additional.ut_offset);
224 }
225};
226
227template <>
228struct fmt::formatter<Service::PSC::Time::LocationName> : fmt::formatter<fmt::string_view> {
229 template <typename FormatContext>
230 auto format(const Service::PSC::Time::LocationName& name, FormatContext& ctx) const {
231 return formatter<string_view>::format(name.data(), ctx);
232 }
233};
234
235template <>
236struct fmt::formatter<Service::PSC::Time::RuleVersion> : fmt::formatter<fmt::string_view> {
237 template <typename FormatContext>
238 auto format(const Service::PSC::Time::RuleVersion& version, FormatContext& ctx) const {
239 return formatter<string_view>::format(version.data(), ctx);
240 }
241};
242
243template <>
244struct fmt::formatter<Service::PSC::Time::ClockSnapshot> : fmt::formatter<fmt::string_view> {
245 template <typename FormatContext>
246 auto format(const Service::PSC::Time::ClockSnapshot& snapshot, FormatContext& ctx) const {
247 return fmt::format_to(
248 ctx.out(),
249 "[user_context={} network_context={} user_time={} network_time={} "
250 "user_calendar_time={} "
251 "network_calendar_time={} user_calendar_additional_time={} "
252 "network_calendar_additional_time={} steady_clock_time_point={} location={} "
253 "is_automatic_correction_enabled={} type={}]",
254 snapshot.user_context, snapshot.network_context, snapshot.user_time,
255 snapshot.network_time, snapshot.user_calendar_time, snapshot.network_calendar_time,
256 snapshot.user_calendar_additional_time, snapshot.network_calendar_additional_time,
257 snapshot.steady_clock_time_point, snapshot.location_name,
258 snapshot.is_automatic_correction_enabled, snapshot.type);
259 }
260};
261
262template <>
263struct fmt::formatter<Service::PSC::Time::ContinuousAdjustmentTimePoint>
264 : fmt::formatter<fmt::string_view> {
265 template <typename FormatContext>
266 auto format(const Service::PSC::Time::ContinuousAdjustmentTimePoint& time_point,
267 FormatContext& ctx) const {
268 return fmt::format_to(ctx.out(),
269 "[rtc_offset={} diff_scale={} shift_amount={} lower={} upper={}]",
270 time_point.rtc_offset, time_point.diff_scale, time_point.shift_amount,
271 time_point.lower, time_point.upper);
272 }
273}; \ No newline at end of file
diff --git a/src/core/hle/service/psc/time/power_state_service.cpp b/src/core/hle/service/psc/time/power_state_service.cpp
index b0ae71bf9..ab1d32c70 100644
--- a/src/core/hle/service/psc/time/power_state_service.cpp
+++ b/src/core/hle/service/psc/time/power_state_service.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/hle/service/cmif_serialization.h"
4#include "core/hle/service/psc/time/power_state_service.h" 5#include "core/hle/service/psc/time/power_state_service.h"
5 6
6namespace Service::PSC::Time { 7namespace Service::PSC::Time {
@@ -11,39 +12,34 @@ IPowerStateRequestHandler::IPowerStateRequestHandler(
11 power_state_request_manager} { 12 power_state_request_manager} {
12 // clang-format off 13 // clang-format off
13 static const FunctionInfo functions[] = { 14 static const FunctionInfo functions[] = {
14 {0, &IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle, "GetPowerStateRequestEventReadableHandle"}, 15 {0, D<&IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle>, "GetPowerStateRequestEventReadableHandle"},
15 {1, &IPowerStateRequestHandler::GetAndClearPowerStateRequest, "GetAndClearPowerStateRequest"}, 16 {1, D<&IPowerStateRequestHandler::GetAndClearPowerStateRequest>, "GetAndClearPowerStateRequest"},
16 }; 17 };
17 // clang-format on 18 // clang-format on
18 19
19 RegisterHandlers(functions); 20 RegisterHandlers(functions);
20} 21}
21 22
22void IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx) { 23Result IPowerStateRequestHandler::GetPowerStateRequestEventReadableHandle(
24 OutCopyHandle<Kernel::KReadableEvent> out_event) {
23 LOG_DEBUG(Service_Time, "called."); 25 LOG_DEBUG(Service_Time, "called.");
24 26
25 IPC::ResponseBuilder rb{ctx, 2, 1}; 27 *out_event = &m_power_state_request_manager.GetReadableEvent();
26 rb.Push(ResultSuccess); 28 R_SUCCEED();
27 rb.PushCopyObjects(m_power_state_request_manager.GetReadableEvent());
28} 29}
29 30
30void IPowerStateRequestHandler::GetAndClearPowerStateRequest(HLERequestContext& ctx) { 31Result IPowerStateRequestHandler::GetAndClearPowerStateRequest(Out<bool> out_cleared,
32 Out<u32> out_priority) {
31 LOG_DEBUG(Service_Time, "called."); 33 LOG_DEBUG(Service_Time, "called.");
32 34
33 u32 priority{}; 35 u32 priority{};
34 auto cleared = m_power_state_request_manager.GetAndClearPowerStateRequest(priority); 36 auto cleared = m_power_state_request_manager.GetAndClearPowerStateRequest(priority);
37 *out_cleared = cleared;
35 38
36 if (cleared) { 39 if (cleared) {
37 IPC::ResponseBuilder rb{ctx, 4}; 40 *out_priority = priority;
38 rb.Push(ResultSuccess);
39 rb.Push(priority);
40 rb.Push(cleared);
41 return;
42 } 41 }
43 42 R_SUCCEED();
44 IPC::ResponseBuilder rb{ctx, 3};
45 rb.Push(ResultSuccess);
46 rb.Push(cleared);
47} 43}
48 44
49} // namespace Service::PSC::Time 45} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/power_state_service.h b/src/core/hle/service/psc/time/power_state_service.h
index 3ebfddb79..56e2c4b87 100644
--- a/src/core/hle/service/psc/time/power_state_service.h
+++ b/src/core/hle/service/psc/time/power_state_service.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/power_state_request_manager.h" 8#include "core/hle/service/psc/time/power_state_request_manager.h"
8#include "core/hle/service/server_manager.h" 9#include "core/hle/service/server_manager.h"
@@ -21,10 +22,10 @@ public:
21 22
22 ~IPowerStateRequestHandler() override = default; 23 ~IPowerStateRequestHandler() override = default;
23 24
24private: 25 Result GetPowerStateRequestEventReadableHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
25 void GetPowerStateRequestEventReadableHandle(HLERequestContext& ctx); 26 Result GetAndClearPowerStateRequest(Out<bool> out_cleared, Out<u32> out_priority);
26 void GetAndClearPowerStateRequest(HLERequestContext& ctx);
27 27
28private:
28 Core::System& m_system; 29 Core::System& m_system;
29 PowerStateRequestManager& m_power_state_request_manager; 30 PowerStateRequestManager& m_power_state_request_manager;
30}; 31};
diff --git a/src/core/hle/service/psc/time/service_manager.cpp b/src/core/hle/service/psc/time/service_manager.cpp
index 60820aa9b..4e1643fcb 100644
--- a/src/core/hle/service/psc/time/service_manager.cpp
+++ b/src/core/hle/service/psc/time/service_manager.cpp
@@ -3,6 +3,7 @@
3 3
4#include "core/core.h" 4#include "core/core.h"
5#include "core/core_timing.h" 5#include "core/core_timing.h"
6#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/psc/time/power_state_service.h" 7#include "core/hle/service/psc/time/power_state_service.h"
7#include "core/hle/service/psc/time/service_manager.h" 8#include "core/hle/service/psc/time/service_manager.h"
8#include "core/hle/service/psc/time/static.h" 9#include "core/hle/service/psc/time/static.h"
@@ -25,24 +26,24 @@ ServiceManager::ServiceManager(Core::System& system_, std::shared_ptr<TimeManage
25 m_local_operation{m_system}, m_network_operation{m_system}, m_ephemeral_operation{m_system} { 26 m_local_operation{m_system}, m_network_operation{m_system}, m_ephemeral_operation{m_system} {
26 // clang-format off 27 // clang-format off
27 static const FunctionInfo functions[] = { 28 static const FunctionInfo functions[] = {
28 {0, &ServiceManager::Handle_GetStaticServiceAsUser, "GetStaticServiceAsUser"}, 29 {0, D<&ServiceManager::GetStaticServiceAsUser>, "GetStaticServiceAsUser"},
29 {5, &ServiceManager::Handle_GetStaticServiceAsAdmin, "GetStaticServiceAsAdmin"}, 30 {5, D<&ServiceManager::GetStaticServiceAsAdmin>, "GetStaticServiceAsAdmin"},
30 {6, &ServiceManager::Handle_GetStaticServiceAsRepair, "GetStaticServiceAsRepair"}, 31 {6, D<&ServiceManager::GetStaticServiceAsRepair>, "GetStaticServiceAsRepair"},
31 {9, &ServiceManager::Handle_GetStaticServiceAsServiceManager, "GetStaticServiceAsServiceManager"}, 32 {9, D<&ServiceManager::GetStaticServiceAsServiceManager>, "GetStaticServiceAsServiceManager"},
32 {10, &ServiceManager::Handle_SetupStandardSteadyClockCore, "SetupStandardSteadyClockCore"}, 33 {10, D<&ServiceManager::SetupStandardSteadyClockCore>, "SetupStandardSteadyClockCore"},
33 {11, &ServiceManager::Handle_SetupStandardLocalSystemClockCore, "SetupStandardLocalSystemClockCore"}, 34 {11, D<&ServiceManager::SetupStandardLocalSystemClockCore>, "SetupStandardLocalSystemClockCore"},
34 {12, &ServiceManager::Handle_SetupStandardNetworkSystemClockCore, "SetupStandardNetworkSystemClockCore"}, 35 {12, D<&ServiceManager::SetupStandardNetworkSystemClockCore>, "SetupStandardNetworkSystemClockCore"},
35 {13, &ServiceManager::Handle_SetupStandardUserSystemClockCore, "SetupStandardUserSystemClockCore"}, 36 {13, D<&ServiceManager::SetupStandardUserSystemClockCore>, "SetupStandardUserSystemClockCore"},
36 {14, &ServiceManager::Handle_SetupTimeZoneServiceCore, "SetupTimeZoneServiceCore"}, 37 {14, D<&ServiceManager::SetupTimeZoneServiceCore>, "SetupTimeZoneServiceCore"},
37 {15, &ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore, "SetupEphemeralNetworkSystemClockCore"}, 38 {15, D<&ServiceManager::SetupEphemeralNetworkSystemClockCore>, "SetupEphemeralNetworkSystemClockCore"},
38 {50, &ServiceManager::Handle_GetStandardLocalClockOperationEvent, "GetStandardLocalClockOperationEvent"}, 39 {50, D<&ServiceManager::GetStandardLocalClockOperationEvent>, "GetStandardLocalClockOperationEvent"},
39 {51, &ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager, "GetStandardNetworkClockOperationEventForServiceManager"}, 40 {51, D<&ServiceManager::GetStandardNetworkClockOperationEventForServiceManager>, "GetStandardNetworkClockOperationEventForServiceManager"},
40 {52, &ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager, "GetEphemeralNetworkClockOperationEventForServiceManager"}, 41 {52, D<&ServiceManager::GetEphemeralNetworkClockOperationEventForServiceManager>, "GetEphemeralNetworkClockOperationEventForServiceManager"},
41 {60, &ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent, "GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent"}, 42 {60, D<&ServiceManager::GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent>, "GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent"},
42 {100, &ServiceManager::Handle_SetStandardSteadyClockBaseTime, "SetStandardSteadyClockBaseTime"}, 43 {100, D<&ServiceManager::SetStandardSteadyClockBaseTime>, "SetStandardSteadyClockBaseTime"},
43 {200, &ServiceManager::Handle_GetClosestAlarmUpdatedEvent, "GetClosestAlarmUpdatedEvent"}, 44 {200, D<&ServiceManager::GetClosestAlarmUpdatedEvent>, "GetClosestAlarmUpdatedEvent"},
44 {201, &ServiceManager::Handle_CheckAndSignalAlarms, "CheckAndSignalAlarms"}, 45 {201, D<&ServiceManager::CheckAndSignalAlarms>, "CheckAndSignalAlarms"},
45 {202, &ServiceManager::Handle_GetClosestAlarmInfo, "GetClosestAlarmInfo "}, 46 {202, D<&ServiceManager::GetClosestAlarmInfo>, "GetClosestAlarmInfo "},
46 }; 47 };
47 // clang-format on 48 // clang-format on
48 RegisterHandlers(functions); 49 RegisterHandlers(functions);
@@ -52,302 +53,39 @@ ServiceManager::ServiceManager(Core::System& system_, std::shared_ptr<TimeManage
52 m_ephemeral_system_context_writer.Link(m_ephemeral_operation); 53 m_ephemeral_system_context_writer.Link(m_ephemeral_operation);
53} 54}
54 55
55void ServiceManager::SetupSAndP() { 56Result ServiceManager::GetStaticServiceAsUser(OutInterface<StaticService> out_service) {
56 if (!m_is_s_and_p_setup) {
57 m_is_s_and_p_setup = true;
58 m_server_manager.RegisterNamedService(
59 "time:s", std::make_shared<StaticService>(
60 m_system, StaticServiceSetupInfo{0, 0, 1, 0, 0, 0}, m_time, "time:s"));
61 m_server_manager.RegisterNamedService("time:p",
62 std::make_shared<IPowerStateRequestHandler>(
63 m_system, m_time->m_power_state_request_manager));
64 }
65}
66
67void ServiceManager::CheckAndSetupServicesSAndP() {
68 if (m_local_system_clock.IsInitialized() && m_user_system_clock.IsInitialized() &&
69 m_network_system_clock.IsInitialized() && m_steady_clock.IsInitialized() &&
70 m_time_zone.IsInitialized() && m_ephemeral_network_clock.IsInitialized()) {
71 SetupSAndP();
72 }
73}
74
75void ServiceManager::Handle_GetStaticServiceAsUser(HLERequestContext& ctx) {
76 LOG_DEBUG(Service_Time, "called."); 57 LOG_DEBUG(Service_Time, "called.");
77 58
78 std::shared_ptr<StaticService> service{}; 59 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, "time:u"));
79 auto res = GetStaticServiceAsUser(service);
80
81 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
82 rb.Push(res);
83 rb.PushIpcInterface<StaticService>(std::move(service));
84}
85
86void ServiceManager::Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx) {
87 LOG_DEBUG(Service_Time, "called.");
88
89 std::shared_ptr<StaticService> service{};
90 auto res = GetStaticServiceAsAdmin(service);
91
92 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
93 rb.Push(res);
94 rb.PushIpcInterface<StaticService>(std::move(service));
95}
96
97void ServiceManager::Handle_GetStaticServiceAsRepair(HLERequestContext& ctx) {
98 LOG_DEBUG(Service_Time, "called.");
99
100 std::shared_ptr<StaticService> service{};
101 auto res = GetStaticServiceAsRepair(service);
102
103 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
104 rb.Push(res);
105 rb.PushIpcInterface<StaticService>(std::move(service));
106}
107
108void ServiceManager::Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx) {
109 LOG_DEBUG(Service_Time, "called.");
110
111 std::shared_ptr<StaticService> service{};
112 auto res = GetStaticServiceAsServiceManager(service);
113
114 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
115 rb.Push(res);
116 rb.PushIpcInterface<StaticService>(std::move(service));
117}
118
119void ServiceManager::Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx) {
120 LOG_DEBUG(Service_Time, "called.");
121
122 struct Parameters {
123 bool reset_detected;
124 Common::UUID clock_source_id;
125 s64 rtc_offset;
126 s64 internal_offset;
127 s64 test_offset;
128 };
129 static_assert(sizeof(Parameters) == 0x30);
130
131 IPC::RequestParser rp{ctx};
132 auto params{rp.PopRaw<Parameters>()};
133
134 auto res = SetupStandardSteadyClockCore(params.clock_source_id, params.rtc_offset,
135 params.internal_offset, params.test_offset,
136 params.reset_detected);
137
138 IPC::ResponseBuilder rb{ctx, 2};
139 rb.Push(res);
140}
141
142void ServiceManager::Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx) {
143 LOG_DEBUG(Service_Time, "called.");
144
145 IPC::RequestParser rp{ctx};
146 auto context{rp.PopRaw<SystemClockContext>()};
147 auto time{rp.Pop<s64>()};
148
149 auto res = SetupStandardLocalSystemClockCore(context, time);
150
151 IPC::ResponseBuilder rb{ctx, 2};
152 rb.Push(res);
153}
154
155void ServiceManager::Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx) {
156 LOG_DEBUG(Service_Time, "called.");
157
158 IPC::RequestParser rp{ctx};
159 auto context{rp.PopRaw<SystemClockContext>()};
160 auto accuracy{rp.Pop<s64>()};
161
162 auto res = SetupStandardNetworkSystemClockCore(context, accuracy);
163
164 IPC::ResponseBuilder rb{ctx, 2};
165 rb.Push(res);
166}
167
168void ServiceManager::Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx) {
169 LOG_DEBUG(Service_Time, "called.");
170
171 struct Parameters {
172 bool automatic_correction;
173 SteadyClockTimePoint time_point;
174 };
175 static_assert(sizeof(Parameters) == 0x20);
176
177 IPC::RequestParser rp{ctx};
178 auto params{rp.PopRaw<Parameters>()};
179
180 auto res = SetupStandardUserSystemClockCore(params.time_point, params.automatic_correction);
181
182 IPC::ResponseBuilder rb{ctx, 2};
183 rb.Push(res);
184}
185
186void ServiceManager::Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx) {
187 LOG_DEBUG(Service_Time, "called.");
188
189 struct Parameters {
190 u32 location_count;
191 LocationName name;
192 SteadyClockTimePoint time_point;
193 RuleVersion rule_version;
194 };
195 static_assert(sizeof(Parameters) == 0x50);
196
197 IPC::RequestParser rp{ctx};
198 auto params{rp.PopRaw<Parameters>()};
199
200 auto rule_buffer{ctx.ReadBuffer()};
201
202 auto res = SetupTimeZoneServiceCore(params.name, params.time_point, params.rule_version,
203 params.location_count, rule_buffer);
204
205 IPC::ResponseBuilder rb{ctx, 2};
206 rb.Push(res);
207}
208
209void ServiceManager::Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx) {
210 LOG_DEBUG(Service_Time, "called.");
211
212 auto res = SetupEphemeralNetworkSystemClockCore();
213
214 IPC::ResponseBuilder rb{ctx, 2};
215 rb.Push(res);
216}
217
218void ServiceManager::Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx) {
219 LOG_DEBUG(Service_Time, "called.");
220
221 Kernel::KEvent* event{};
222 auto res = GetStandardLocalClockOperationEvent(&event);
223
224 IPC::ResponseBuilder rb{ctx, 2, 1};
225 rb.Push(res);
226 rb.PushCopyObjects(event->GetReadableEvent());
227}
228
229void ServiceManager::Handle_GetStandardNetworkClockOperationEventForServiceManager(
230 HLERequestContext& ctx) {
231 LOG_DEBUG(Service_Time, "called.");
232
233 Kernel::KEvent* event{};
234 auto res = GetStandardNetworkClockOperationEventForServiceManager(&event);
235
236 IPC::ResponseBuilder rb{ctx, 2, 1};
237 rb.Push(res);
238 rb.PushCopyObjects(event);
239}
240
241void ServiceManager::Handle_GetEphemeralNetworkClockOperationEventForServiceManager(
242 HLERequestContext& ctx) {
243 LOG_DEBUG(Service_Time, "called.");
244
245 Kernel::KEvent* event{};
246 auto res = GetEphemeralNetworkClockOperationEventForServiceManager(&event);
247
248 IPC::ResponseBuilder rb{ctx, 2, 1};
249 rb.Push(res);
250 rb.PushCopyObjects(event);
251}
252
253void ServiceManager::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
254 HLERequestContext& ctx) {
255 LOG_DEBUG(Service_Time, "called.");
256
257 Kernel::KEvent* event{};
258 auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(&event);
259
260 IPC::ResponseBuilder rb{ctx, 2, 1};
261 rb.Push(res);
262 rb.PushCopyObjects(event);
263}
264
265void ServiceManager::Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx) {
266 LOG_DEBUG(Service_Time, "called.");
267
268 IPC::RequestParser rp{ctx};
269 auto base_time{rp.Pop<s64>()};
270
271 auto res = SetStandardSteadyClockBaseTime(base_time);
272
273 IPC::ResponseBuilder rb{ctx, 2};
274 rb.Push(res);
275} 60}
276 61
277void ServiceManager::Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx) { 62Result ServiceManager::GetStaticServiceAsAdmin(OutInterface<StaticService> out_service) {
278 LOG_DEBUG(Service_Time, "called."); 63 LOG_DEBUG(Service_Time, "called.");
279 64
280 Kernel::KEvent* event{}; 65 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, "time:a"));
281 auto res = GetClosestAlarmUpdatedEvent(&event);
282
283 IPC::ResponseBuilder rb{ctx, 3};
284 rb.Push(res);
285 rb.PushCopyObjects(event->GetReadableEvent());
286} 66}
287 67
288void ServiceManager::Handle_CheckAndSignalAlarms(HLERequestContext& ctx) { 68Result ServiceManager::GetStaticServiceAsRepair(OutInterface<StaticService> out_service) {
289 LOG_DEBUG(Service_Time, "called."); 69 LOG_DEBUG(Service_Time, "called.");
290 70
291 auto res = CheckAndSignalAlarms(); 71 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, "time:r"));
292
293 IPC::ResponseBuilder rb{ctx, 2};
294 rb.Push(res);
295} 72}
296 73
297void ServiceManager::Handle_GetClosestAlarmInfo(HLERequestContext& ctx) { 74Result ServiceManager::GetStaticServiceAsServiceManager(OutInterface<StaticService> out_service) {
298 LOG_DEBUG(Service_Time, "called."); 75 LOG_DEBUG(Service_Time, "called.");
299 76
300 AlarmInfo alarm_info{};
301 bool is_valid{};
302 s64 time{};
303 auto res = GetClosestAlarmInfo(is_valid, alarm_info, time);
304
305 struct OutParameters {
306 bool is_valid;
307 AlarmInfo alarm_info;
308 s64 time;
309 };
310 static_assert(sizeof(OutParameters) == 0x20);
311
312 OutParameters out_params{
313 .is_valid = is_valid,
314 .alarm_info = alarm_info,
315 .time = time,
316 };
317
318 IPC::ResponseBuilder rb{ctx, 2 + sizeof(OutParameters) / sizeof(u32)};
319 rb.Push(res);
320 rb.PushRaw<OutParameters>(out_params);
321}
322
323// =============================== Implementations ===========================
324
325Result ServiceManager::GetStaticService(std::shared_ptr<StaticService>& out_service,
326 StaticServiceSetupInfo setup_info, const char* name) {
327 out_service = std::make_shared<StaticService>(m_system, setup_info, m_time, name);
328 R_SUCCEED();
329}
330
331Result ServiceManager::GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service) {
332 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 0, 0}, "time:u"));
333}
334
335Result ServiceManager::GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service) {
336 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 0, 1, 0, 0}, "time:a"));
337}
338
339Result ServiceManager::GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service) {
340 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{0, 0, 0, 0, 1, 0}, "time:r"));
341}
342
343Result ServiceManager::GetStaticServiceAsServiceManager(
344 std::shared_ptr<StaticService>& out_service) {
345 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 1, 1, 1, 0}, "time:sm")); 77 R_RETURN(GetStaticService(out_service, StaticServiceSetupInfo{1, 1, 1, 1, 1, 0}, "time:sm"));
346} 78}
347 79
348Result ServiceManager::SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset, 80Result ServiceManager::SetupStandardSteadyClockCore(bool is_rtc_reset_detected,
349 s64 internal_offset, s64 test_offset, 81 Common::UUID& clock_source_id, s64 rtc_offset,
350 bool is_rtc_reset_detected) { 82 s64 internal_offset, s64 test_offset) {
83 LOG_DEBUG(Service_Time,
84 "called. is_rtc_reset_detected={} clock_source_id={} rtc_offset={} "
85 "internal_offset={} test_offset={}",
86 is_rtc_reset_detected, clock_source_id.RawString(), rtc_offset, internal_offset,
87 test_offset);
88
351 m_steady_clock.Initialize(clock_source_id, rtc_offset, internal_offset, test_offset, 89 m_steady_clock.Initialize(clock_source_id, rtc_offset, internal_offset, test_offset,
352 is_rtc_reset_detected); 90 is_rtc_reset_detected);
353 auto time = m_steady_clock.GetRawTime(); 91 auto time = m_steady_clock.GetRawTime();
@@ -365,6 +103,10 @@ Result ServiceManager::SetupStandardSteadyClockCore(Common::UUID& clock_source_i
365} 103}
366 104
367Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time) { 105Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time) {
106 LOG_DEBUG(Service_Time,
107 "called. context={} context.steady_time_point.clock_source_id={} time={}", context,
108 context.steady_time_point.clock_source_id.RawString(), time);
109
368 m_local_system_clock.SetContextWriter(m_local_system_context_writer); 110 m_local_system_clock.SetContextWriter(m_local_system_context_writer);
369 m_local_system_clock.Initialize(context, time); 111 m_local_system_clock.Initialize(context, time);
370 112
@@ -374,12 +116,12 @@ Result ServiceManager::SetupStandardLocalSystemClockCore(SystemClockContext& con
374 116
375Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& context, 117Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& context,
376 s64 accuracy) { 118 s64 accuracy) {
119 LOG_DEBUG(Service_Time, "called. context={} steady_time_point.clock_source_id={} accuracy={}",
120 context, context.steady_time_point.clock_source_id.RawString(), accuracy);
121
377 // TODO this is a hack! The network clock should be updated independently, from the ntc service 122 // TODO this is a hack! The network clock should be updated independently, from the ntc service
378 // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot 123 // and maybe elsewhere. We do not do that, so fix the clock to the local clock.
379 // to avoid it being stuck at 0. 124 m_local_system_clock.GetContext(context);
380 if (context == Service::PSC::Time::SystemClockContext{}) {
381 m_local_system_clock.GetContext(context);
382 }
383 125
384 m_network_system_clock.SetContextWriter(m_network_system_context_writer); 126 m_network_system_clock.SetContextWriter(m_network_system_context_writer);
385 m_network_system_clock.Initialize(context, accuracy); 127 m_network_system_clock.Initialize(context, accuracy);
@@ -388,14 +130,10 @@ Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& c
388 R_SUCCEED(); 130 R_SUCCEED();
389} 131}
390 132
391Result ServiceManager::SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point, 133Result ServiceManager::SetupStandardUserSystemClockCore(bool automatic_correction,
392 bool automatic_correction) { 134 SteadyClockTimePoint& time_point) {
393 // TODO this is a hack! The user clock should be updated independently, from the ntc service 135 LOG_DEBUG(Service_Time, "called. automatic_correction={} time_point={} clock_source_id={}",
394 // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot 136 automatic_correction, time_point, time_point.clock_source_id.RawString());
395 // to avoid it being stuck at 0.
396 if (time_point == Service::PSC::Time::SteadyClockTimePoint{}) {
397 m_local_system_clock.GetCurrentTimePoint(time_point);
398 }
399 137
400 m_user_system_clock.SetAutomaticCorrection(automatic_correction); 138 m_user_system_clock.SetAutomaticCorrection(automatic_correction);
401 m_user_system_clock.SetTimePointAndSignal(time_point); 139 m_user_system_clock.SetTimePointAndSignal(time_point);
@@ -406,10 +144,16 @@ Result ServiceManager::SetupStandardUserSystemClockCore(SteadyClockTimePoint& ti
406 R_SUCCEED(); 144 R_SUCCEED();
407} 145}
408 146
409Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name, 147Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name, RuleVersion& rule_version,
148 u32 location_count,
410 SteadyClockTimePoint& time_point, 149 SteadyClockTimePoint& time_point,
411 RuleVersion& rule_version, u32 location_count, 150 InBuffer<BufferAttr_HipcAutoSelect> rule_buffer) {
412 std::span<const u8> rule_buffer) { 151 LOG_DEBUG(Service_Time,
152 "called. name={} rule_version={} location_count={} time_point={} "
153 "clock_source_id={}",
154 name, rule_version, location_count, time_point,
155 time_point.clock_source_id.RawString());
156
413 if (m_time_zone.ParseBinary(name, rule_buffer) != ResultSuccess) { 157 if (m_time_zone.ParseBinary(name, rule_buffer) != ResultSuccess) {
414 LOG_ERROR(Service_Time, "Failed to parse time zone binary!"); 158 LOG_ERROR(Service_Time, "Failed to parse time zone binary!");
415 } 159 }
@@ -424,6 +168,8 @@ Result ServiceManager::SetupTimeZoneServiceCore(LocationName& name,
424} 168}
425 169
426Result ServiceManager::SetupEphemeralNetworkSystemClockCore() { 170Result ServiceManager::SetupEphemeralNetworkSystemClockCore() {
171 LOG_DEBUG(Service_Time, "called.");
172
427 m_ephemeral_network_clock.SetContextWriter(m_ephemeral_system_context_writer); 173 m_ephemeral_network_clock.SetContextWriter(m_ephemeral_system_context_writer);
428 m_ephemeral_network_clock.SetInitialized(); 174 m_ephemeral_network_clock.SetInitialized();
429 175
@@ -431,30 +177,41 @@ Result ServiceManager::SetupEphemeralNetworkSystemClockCore() {
431 R_SUCCEED(); 177 R_SUCCEED();
432} 178}
433 179
434Result ServiceManager::GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event) { 180Result ServiceManager::GetStandardLocalClockOperationEvent(
435 *out_event = m_local_operation.m_event; 181 OutCopyHandle<Kernel::KReadableEvent> out_event) {
182 LOG_DEBUG(Service_Time, "called.");
183
184 *out_event = &m_local_operation.m_event->GetReadableEvent();
436 R_SUCCEED(); 185 R_SUCCEED();
437} 186}
438 187
439Result ServiceManager::GetStandardNetworkClockOperationEventForServiceManager( 188Result ServiceManager::GetStandardNetworkClockOperationEventForServiceManager(
440 Kernel::KEvent** out_event) { 189 OutCopyHandle<Kernel::KReadableEvent> out_event) {
441 *out_event = m_network_operation.m_event; 190 LOG_DEBUG(Service_Time, "called.");
191
192 *out_event = &m_network_operation.m_event->GetReadableEvent();
442 R_SUCCEED(); 193 R_SUCCEED();
443} 194}
444 195
445Result ServiceManager::GetEphemeralNetworkClockOperationEventForServiceManager( 196Result ServiceManager::GetEphemeralNetworkClockOperationEventForServiceManager(
446 Kernel::KEvent** out_event) { 197 OutCopyHandle<Kernel::KReadableEvent> out_event) {
447 *out_event = m_ephemeral_operation.m_event; 198 LOG_DEBUG(Service_Time, "called.");
199
200 *out_event = &m_ephemeral_operation.m_event->GetReadableEvent();
448 R_SUCCEED(); 201 R_SUCCEED();
449} 202}
450 203
451Result ServiceManager::GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent( 204Result ServiceManager::GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
452 Kernel::KEvent** out_event) { 205 OutCopyHandle<Kernel::KReadableEvent> out_event) {
453 *out_event = &m_user_system_clock.GetEvent(); 206 LOG_DEBUG(Service_Time, "called.");
207
208 *out_event = &m_user_system_clock.GetEvent().GetReadableEvent();
454 R_SUCCEED(); 209 R_SUCCEED();
455} 210}
456 211
457Result ServiceManager::SetStandardSteadyClockBaseTime(s64 base_time) { 212Result ServiceManager::SetStandardSteadyClockBaseTime(s64 base_time) {
213 LOG_DEBUG(Service_Time, "called. base_time={}", base_time);
214
458 m_steady_clock.SetRtcOffset(base_time); 215 m_steady_clock.SetRtcOffset(base_time);
459 auto time = m_steady_clock.GetRawTime(); 216 auto time = m_steady_clock.GetRawTime();
460 auto ticks = m_system.CoreTiming().GetClockTicks(); 217 auto ticks = m_system.CoreTiming().GetClockTicks();
@@ -468,26 +225,63 @@ Result ServiceManager::SetStandardSteadyClockBaseTime(s64 base_time) {
468 R_SUCCEED(); 225 R_SUCCEED();
469} 226}
470 227
471Result ServiceManager::GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event) { 228Result ServiceManager::GetClosestAlarmUpdatedEvent(
472 *out_event = &m_alarms.GetEvent(); 229 OutCopyHandle<Kernel::KReadableEvent> out_event) {
230 LOG_DEBUG(Service_Time, "called.");
231
232 *out_event = &m_alarms.GetEvent().GetReadableEvent();
473 R_SUCCEED(); 233 R_SUCCEED();
474} 234}
475 235
476Result ServiceManager::CheckAndSignalAlarms() { 236Result ServiceManager::CheckAndSignalAlarms() {
237 LOG_DEBUG(Service_Time, "called.");
238
477 m_alarms.CheckAndSignal(); 239 m_alarms.CheckAndSignal();
478 R_SUCCEED(); 240 R_SUCCEED();
479} 241}
480 242
481Result ServiceManager::GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time) { 243Result ServiceManager::GetClosestAlarmInfo(Out<bool> out_is_valid, Out<AlarmInfo> out_info,
244 Out<s64> out_time) {
482 Alarm* alarm{nullptr}; 245 Alarm* alarm{nullptr};
483 out_is_valid = m_alarms.GetClosestAlarm(&alarm); 246 *out_is_valid = m_alarms.GetClosestAlarm(&alarm);
484 if (out_is_valid) { 247 if (*out_is_valid) {
485 out_info = { 248 *out_info = {
486 .alert_time = alarm->GetAlertTime(), 249 .alert_time = alarm->GetAlertTime(),
487 .priority = alarm->GetPriority(), 250 .priority = alarm->GetPriority(),
488 }; 251 };
489 out_time = m_alarms.GetRawTime(); 252 *out_time = m_alarms.GetRawTime();
253 }
254
255 LOG_DEBUG(Service_Time,
256 "called. out_is_valid={} out_info.alert_time={} out_info.priority={}, out_time={}",
257 *out_is_valid, out_info->alert_time, out_info->priority, *out_time);
258
259 R_SUCCEED();
260}
261
262void ServiceManager::CheckAndSetupServicesSAndP() {
263 if (m_local_system_clock.IsInitialized() && m_user_system_clock.IsInitialized() &&
264 m_network_system_clock.IsInitialized() && m_steady_clock.IsInitialized() &&
265 m_time_zone.IsInitialized() && m_ephemeral_network_clock.IsInitialized()) {
266 SetupSAndP();
267 }
268}
269
270void ServiceManager::SetupSAndP() {
271 if (!m_is_s_and_p_setup) {
272 m_is_s_and_p_setup = true;
273 m_server_manager.RegisterNamedService(
274 "time:s", std::make_shared<StaticService>(
275 m_system, StaticServiceSetupInfo{0, 0, 1, 0, 0, 0}, m_time, "time:s"));
276 m_server_manager.RegisterNamedService("time:p",
277 std::make_shared<IPowerStateRequestHandler>(
278 m_system, m_time->m_power_state_request_manager));
490 } 279 }
280}
281
282Result ServiceManager::GetStaticService(OutInterface<StaticService> out_service,
283 StaticServiceSetupInfo setup_info, const char* name) {
284 *out_service = std::make_shared<StaticService>(m_system, setup_info, m_time, name);
491 R_SUCCEED(); 285 R_SUCCEED();
492} 286}
493 287
diff --git a/src/core/hle/service/psc/time/service_manager.h b/src/core/hle/service/psc/time/service_manager.h
index 1d9952317..25d361d4f 100644
--- a/src/core/hle/service/psc/time/service_manager.h
+++ b/src/core/hle/service/psc/time/service_manager.h
@@ -6,6 +6,7 @@
6#include <list> 6#include <list>
7#include <memory> 7#include <memory>
8 8
9#include "core/hle/service/cmif_types.h"
9#include "core/hle/service/ipc_helpers.h" 10#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/psc/time/common.h" 11#include "core/hle/service/psc/time/common.h"
11#include "core/hle/service/psc/time/manager.h" 12#include "core/hle/service/psc/time/manager.h"
@@ -29,55 +30,38 @@ public:
29 ServerManager* server_manager); 30 ServerManager* server_manager);
30 ~ServiceManager() override = default; 31 ~ServiceManager() override = default;
31 32
32 Result GetStaticServiceAsUser(std::shared_ptr<StaticService>& out_service); 33 Result GetStaticServiceAsUser(OutInterface<StaticService> out_service);
33 Result GetStaticServiceAsAdmin(std::shared_ptr<StaticService>& out_service); 34 Result GetStaticServiceAsAdmin(OutInterface<StaticService> out_service);
34 Result GetStaticServiceAsRepair(std::shared_ptr<StaticService>& out_service); 35 Result GetStaticServiceAsRepair(OutInterface<StaticService> out_service);
35 Result GetStaticServiceAsServiceManager(std::shared_ptr<StaticService>& out_service); 36 Result GetStaticServiceAsServiceManager(OutInterface<StaticService> out_service);
36 Result SetupStandardSteadyClockCore(Common::UUID& clock_source_id, s64 rtc_offset, 37 Result SetupStandardSteadyClockCore(bool is_rtc_reset_detected, Common::UUID& clock_source_id,
37 s64 internal_offset, s64 test_offset, 38 s64 rtc_offset, s64 internal_offset, s64 test_offset);
38 bool is_rtc_reset_detected);
39 Result SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time); 39 Result SetupStandardLocalSystemClockCore(SystemClockContext& context, s64 time);
40 Result SetupStandardNetworkSystemClockCore(SystemClockContext& context, s64 accuracy); 40 Result SetupStandardNetworkSystemClockCore(SystemClockContext& context, s64 accuracy);
41 Result SetupStandardUserSystemClockCore(SteadyClockTimePoint& time_point, 41 Result SetupStandardUserSystemClockCore(bool automatic_correction,
42 bool automatic_correction); 42 SteadyClockTimePoint& time_point);
43 Result SetupTimeZoneServiceCore(LocationName& name, SteadyClockTimePoint& time_point, 43 Result SetupTimeZoneServiceCore(LocationName& name, RuleVersion& rule_version,
44 RuleVersion& rule_version, u32 location_count, 44 u32 location_count, SteadyClockTimePoint& time_point,
45 std::span<const u8> rule_buffer); 45 InBuffer<BufferAttr_HipcAutoSelect> rule_buffer);
46 Result SetupEphemeralNetworkSystemClockCore(); 46 Result SetupEphemeralNetworkSystemClockCore();
47 Result GetStandardLocalClockOperationEvent(Kernel::KEvent** out_event); 47 Result GetStandardLocalClockOperationEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
48 Result GetStandardNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event); 48 Result GetStandardNetworkClockOperationEventForServiceManager(
49 Result GetEphemeralNetworkClockOperationEventForServiceManager(Kernel::KEvent** out_event); 49 OutCopyHandle<Kernel::KReadableEvent> out_event);
50 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(Kernel::KEvent** out_event); 50 Result GetEphemeralNetworkClockOperationEventForServiceManager(
51 OutCopyHandle<Kernel::KReadableEvent> out_event);
52 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(
53 OutCopyHandle<Kernel::KReadableEvent> out_event);
51 Result SetStandardSteadyClockBaseTime(s64 base_time); 54 Result SetStandardSteadyClockBaseTime(s64 base_time);
52 Result GetClosestAlarmUpdatedEvent(Kernel::KEvent** out_event); 55 Result GetClosestAlarmUpdatedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
53 Result CheckAndSignalAlarms(); 56 Result CheckAndSignalAlarms();
54 Result GetClosestAlarmInfo(bool& out_is_valid, AlarmInfo& out_info, s64& out_time); 57 Result GetClosestAlarmInfo(Out<bool> out_is_valid, Out<AlarmInfo> out_info, Out<s64> out_time);
55 58
56private: 59private:
57 void CheckAndSetupServicesSAndP(); 60 void CheckAndSetupServicesSAndP();
58 void SetupSAndP(); 61 void SetupSAndP();
59 Result GetStaticService(std::shared_ptr<StaticService>& out_service, 62 Result GetStaticService(OutInterface<StaticService> out_service,
60 StaticServiceSetupInfo setup_info, const char* name); 63 StaticServiceSetupInfo setup_info, const char* name);
61 64
62 void Handle_GetStaticServiceAsUser(HLERequestContext& ctx);
63 void Handle_GetStaticServiceAsAdmin(HLERequestContext& ctx);
64 void Handle_GetStaticServiceAsRepair(HLERequestContext& ctx);
65 void Handle_GetStaticServiceAsServiceManager(HLERequestContext& ctx);
66 void Handle_SetupStandardSteadyClockCore(HLERequestContext& ctx);
67 void Handle_SetupStandardLocalSystemClockCore(HLERequestContext& ctx);
68 void Handle_SetupStandardNetworkSystemClockCore(HLERequestContext& ctx);
69 void Handle_SetupStandardUserSystemClockCore(HLERequestContext& ctx);
70 void Handle_SetupTimeZoneServiceCore(HLERequestContext& ctx);
71 void Handle_SetupEphemeralNetworkSystemClockCore(HLERequestContext& ctx);
72 void Handle_GetStandardLocalClockOperationEvent(HLERequestContext& ctx);
73 void Handle_GetStandardNetworkClockOperationEventForServiceManager(HLERequestContext& ctx);
74 void Handle_GetEphemeralNetworkClockOperationEventForServiceManager(HLERequestContext& ctx);
75 void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedEvent(HLERequestContext& ctx);
76 void Handle_SetStandardSteadyClockBaseTime(HLERequestContext& ctx);
77 void Handle_GetClosestAlarmUpdatedEvent(HLERequestContext& ctx);
78 void Handle_CheckAndSignalAlarms(HLERequestContext& ctx);
79 void Handle_GetClosestAlarmInfo(HLERequestContext& ctx);
80
81 Core::System& m_system; 65 Core::System& m_system;
82 std::shared_ptr<TimeManager> m_time; 66 std::shared_ptr<TimeManager> m_time;
83 ServerManager& m_server_manager; 67 ServerManager& m_server_manager;
diff --git a/src/core/hle/service/psc/time/static.cpp b/src/core/hle/service/psc/time/static.cpp
index 6f8cf3f88..3ca3311af 100644
--- a/src/core/hle/service/psc/time/static.cpp
+++ b/src/core/hle/service/psc/time/static.cpp
@@ -1,9 +1,11 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/scope_exit.h"
4#include "core/core.h" 5#include "core/core.h"
5#include "core/core_timing.h" 6#include "core/core_timing.h"
6#include "core/hle/kernel/k_shared_memory.h" 7#include "core/hle/kernel/k_shared_memory.h"
8#include "core/hle/service/cmif_serialization.h"
7#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h" 9#include "core/hle/service/psc/time/clocks/ephemeral_network_system_clock_core.h"
8#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h" 10#include "core/hle/service/psc/time/clocks/standard_local_system_clock_core.h"
9#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h" 11#include "core/hle/service/psc/time/clocks/standard_network_system_clock_core.h"
@@ -39,358 +41,122 @@ StaticService::StaticService(Core::System& system_, StaticServiceSetupInfo setup
39 m_time->m_shared_memory} { 41 m_time->m_shared_memory} {
40 // clang-format off 42 // clang-format off
41 static const FunctionInfo functions[] = { 43 static const FunctionInfo functions[] = {
42 {0, &StaticService::Handle_GetStandardUserSystemClock, "GetStandardUserSystemClock"}, 44 {0, D<&StaticService::GetStandardUserSystemClock>, "GetStandardUserSystemClock"},
43 {1, &StaticService::Handle_GetStandardNetworkSystemClock, "GetStandardNetworkSystemClock"}, 45 {1, D<&StaticService::GetStandardNetworkSystemClock>, "GetStandardNetworkSystemClock"},
44 {2, &StaticService::Handle_GetStandardSteadyClock, "GetStandardSteadyClock"}, 46 {2, D<&StaticService::GetStandardSteadyClock>, "GetStandardSteadyClock"},
45 {3, &StaticService::Handle_GetTimeZoneService, "GetTimeZoneService"}, 47 {3, D<&StaticService::GetTimeZoneService>, "GetTimeZoneService"},
46 {4, &StaticService::Handle_GetStandardLocalSystemClock, "GetStandardLocalSystemClock"}, 48 {4, D<&StaticService::GetStandardLocalSystemClock>, "GetStandardLocalSystemClock"},
47 {5, &StaticService::Handle_GetEphemeralNetworkSystemClock, "GetEphemeralNetworkSystemClock"}, 49 {5, D<&StaticService::GetEphemeralNetworkSystemClock>, "GetEphemeralNetworkSystemClock"},
48 {20, &StaticService::Handle_GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, 50 {20, D<&StaticService::GetSharedMemoryNativeHandle>, "GetSharedMemoryNativeHandle"},
49 {50, &StaticService::Handle_SetStandardSteadyClockInternalOffset, "SetStandardSteadyClockInternalOffset"}, 51 {50, D<&StaticService::SetStandardSteadyClockInternalOffset>, "SetStandardSteadyClockInternalOffset"},
50 {51, &StaticService::Handle_GetStandardSteadyClockRtcValue, "GetStandardSteadyClockRtcValue"}, 52 {51, D<&StaticService::GetStandardSteadyClockRtcValue>, "GetStandardSteadyClockRtcValue"},
51 {100, &StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, 53 {100, D<&StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled>, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
52 {101, &StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, 54 {101, D<&StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled>, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
53 {102, &StaticService::Handle_GetStandardUserSystemClockInitialYear, "GetStandardUserSystemClockInitialYear"}, 55 {102, D<&StaticService::GetStandardUserSystemClockInitialYear>, "GetStandardUserSystemClockInitialYear"},
54 {200, &StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, 56 {200, D<&StaticService::IsStandardNetworkSystemClockAccuracySufficient>, "IsStandardNetworkSystemClockAccuracySufficient"},
55 {201, &StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, 57 {201, D<&StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime>, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
56 {300, &StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, 58 {300, D<&StaticService::CalculateMonotonicSystemClockBaseTimePoint>, "CalculateMonotonicSystemClockBaseTimePoint"},
57 {400, &StaticService::Handle_GetClockSnapshot, "GetClockSnapshot"}, 59 {400, D<&StaticService::GetClockSnapshot>, "GetClockSnapshot"},
58 {401, &StaticService::Handle_GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, 60 {401, D<&StaticService::GetClockSnapshotFromSystemClockContext>, "GetClockSnapshotFromSystemClockContext"},
59 {500, &StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, 61 {500, D<&StaticService::CalculateStandardUserSystemClockDifferenceByUser>, "CalculateStandardUserSystemClockDifferenceByUser"},
60 {501, &StaticService::Handle_CalculateSpanBetween, "CalculateSpanBetween"}, 62 {501, D<&StaticService::CalculateSpanBetween>, "CalculateSpanBetween"},
61 }; 63 };
62 // clang-format on 64 // clang-format on
63 65
64 RegisterHandlers(functions); 66 RegisterHandlers(functions);
65} 67}
66 68
67Result StaticService::GetClockSnapshotImpl(ClockSnapshot& out_snapshot, 69Result StaticService::GetStandardUserSystemClock(OutInterface<SystemClock> out_service) {
68 SystemClockContext& user_context,
69 SystemClockContext& network_context, TimeType type) {
70 out_snapshot.user_context = user_context;
71 out_snapshot.network_context = network_context;
72
73 R_TRY(
74 m_time->m_standard_steady_clock.GetCurrentTimePoint(out_snapshot.steady_clock_time_point));
75
76 out_snapshot.is_automatic_correction_enabled = m_user_system_clock.GetAutomaticCorrection();
77
78 R_TRY(m_time_zone.GetLocationName(out_snapshot.location_name));
79
80 R_TRY(GetTimeFromTimePointAndContext(
81 &out_snapshot.user_time, out_snapshot.steady_clock_time_point, out_snapshot.user_context));
82
83 R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.user_calendar_time,
84 out_snapshot.user_calendar_additional_time,
85 out_snapshot.user_time));
86
87 if (GetTimeFromTimePointAndContext(&out_snapshot.network_time,
88 out_snapshot.steady_clock_time_point,
89 out_snapshot.network_context) != ResultSuccess) {
90 out_snapshot.network_time = 0;
91 }
92
93 R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot.network_calendar_time,
94 out_snapshot.network_calendar_additional_time,
95 out_snapshot.network_time));
96 out_snapshot.type = type;
97 out_snapshot.unk_CE = 0;
98 R_SUCCEED();
99}
100
101void StaticService::Handle_GetStandardUserSystemClock(HLERequestContext& ctx) {
102 LOG_DEBUG(Service_Time, "called.");
103
104 std::shared_ptr<SystemClock> service{};
105 auto res = GetStandardUserSystemClock(service);
106
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(res);
109 rb.PushIpcInterface<SystemClock>(std::move(service));
110}
111
112void StaticService::Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx) {
113 LOG_DEBUG(Service_Time, "called."); 70 LOG_DEBUG(Service_Time, "called.");
114 71
115 std::shared_ptr<SystemClock> service{}; 72 *out_service = std::make_shared<SystemClock>(m_system, m_user_system_clock,
116 auto res = GetStandardNetworkSystemClock(service); 73 m_setup_info.can_write_user_clock,
117 74 m_setup_info.can_write_uninitialized_clock);
118 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 75 R_SUCCEED();
119 rb.Push(res);
120 rb.PushIpcInterface<SystemClock>(std::move(service));
121}
122
123void StaticService::Handle_GetStandardSteadyClock(HLERequestContext& ctx) {
124 LOG_DEBUG(Service_Time, "called.");
125
126 std::shared_ptr<SteadyClock> service{};
127 auto res = GetStandardSteadyClock(service);
128
129 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
130 rb.Push(res);
131 rb.PushIpcInterface(std::move(service));
132}
133
134void StaticService::Handle_GetTimeZoneService(HLERequestContext& ctx) {
135 LOG_DEBUG(Service_Time, "called.");
136
137 std::shared_ptr<TimeZoneService> service{};
138 auto res = GetTimeZoneService(service);
139
140 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
141 rb.Push(res);
142 rb.PushIpcInterface(std::move(service));
143}
144
145void StaticService::Handle_GetStandardLocalSystemClock(HLERequestContext& ctx) {
146 LOG_DEBUG(Service_Time, "called.");
147
148 std::shared_ptr<SystemClock> service{};
149 auto res = GetStandardLocalSystemClock(service);
150
151 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
152 rb.Push(res);
153 rb.PushIpcInterface<SystemClock>(std::move(service));
154}
155
156void StaticService::Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx) {
157 LOG_DEBUG(Service_Time, "called.");
158
159 std::shared_ptr<SystemClock> service{};
160 auto res = GetEphemeralNetworkSystemClock(service);
161
162 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
163 rb.Push(res);
164 rb.PushIpcInterface<SystemClock>(std::move(service));
165}
166
167void StaticService::Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx) {
168 LOG_DEBUG(Service_Time, "called.");
169
170 Kernel::KSharedMemory* shared_memory{};
171 auto res = GetSharedMemoryNativeHandle(&shared_memory);
172
173 IPC::ResponseBuilder rb{ctx, 2, 1};
174 rb.Push(res);
175 rb.PushCopyObjects(shared_memory);
176}
177
178void StaticService::Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx) {
179 LOG_DEBUG(Service_Time, "called.");
180
181 IPC::ResponseBuilder rb{ctx, 2};
182 rb.Push(m_setup_info.can_write_steady_clock ? ResultNotImplemented : ResultPermissionDenied);
183}
184
185void StaticService::Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx) {
186 LOG_DEBUG(Service_Time, "called.");
187
188 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(ResultNotImplemented);
190}
191
192void StaticService::Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(
193 HLERequestContext& ctx) {
194 LOG_DEBUG(Service_Time, "called.");
195
196 bool is_enabled{};
197 auto res = IsStandardUserSystemClockAutomaticCorrectionEnabled(is_enabled);
198
199 IPC::ResponseBuilder rb{ctx, 3};
200 rb.Push(res);
201 rb.Push<bool>(is_enabled);
202}
203
204void StaticService::Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(
205 HLERequestContext& ctx) {
206 LOG_DEBUG(Service_Time, "called.");
207
208 IPC::RequestParser rp{ctx};
209 auto automatic_correction{rp.Pop<bool>()};
210
211 auto res = SetStandardUserSystemClockAutomaticCorrectionEnabled(automatic_correction);
212
213 IPC::ResponseBuilder rb{ctx, 2};
214 rb.Push(res);
215}
216
217void StaticService::Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx) {
218 LOG_DEBUG(Service_Time, "called.");
219
220 IPC::ResponseBuilder rb{ctx, 2};
221 rb.Push(ResultNotImplemented);
222}
223
224void StaticService::Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx) {
225 LOG_DEBUG(Service_Time, "called.");
226
227 bool is_sufficient{};
228 auto res = IsStandardNetworkSystemClockAccuracySufficient(is_sufficient);
229
230 IPC::ResponseBuilder rb{ctx, 3};
231 rb.Push(res);
232 rb.Push<bool>(is_sufficient);
233} 76}
234 77
235void StaticService::Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 78Result StaticService::GetStandardNetworkSystemClock(OutInterface<SystemClock> out_service) {
236 HLERequestContext& ctx) {
237 LOG_DEBUG(Service_Time, "called."); 79 LOG_DEBUG(Service_Time, "called.");
238 80
239 SteadyClockTimePoint time_point{}; 81 *out_service = std::make_shared<SystemClock>(m_system, m_network_system_clock,
240 auto res = GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(time_point); 82 m_setup_info.can_write_network_clock,
241 83 m_setup_info.can_write_uninitialized_clock);
242 IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)}; 84 R_SUCCEED();
243 rb.Push(res);
244 rb.PushRaw<SteadyClockTimePoint>(time_point);
245} 85}
246 86
247void StaticService::Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx) { 87Result StaticService::GetStandardSteadyClock(OutInterface<SteadyClock> out_service) {
248 LOG_DEBUG(Service_Time, "called."); 88 LOG_DEBUG(Service_Time, "called.");
249 89
250 IPC::RequestParser rp{ctx}; 90 *out_service =
251 auto context{rp.PopRaw<SystemClockContext>()}; 91 std::make_shared<SteadyClock>(m_system, m_time, m_setup_info.can_write_steady_clock,
252 92 m_setup_info.can_write_uninitialized_clock);
253 s64 time{}; 93 R_SUCCEED();
254 auto res = CalculateMonotonicSystemClockBaseTimePoint(time, context);
255
256 IPC::ResponseBuilder rb{ctx, 4};
257 rb.Push(res);
258 rb.Push<s64>(time);
259} 94}
260 95
261void StaticService::Handle_GetClockSnapshot(HLERequestContext& ctx) { 96Result StaticService::GetTimeZoneService(OutInterface<TimeZoneService> out_service) {
262 LOG_DEBUG(Service_Time, "called."); 97 LOG_DEBUG(Service_Time, "called.");
263 98
264 IPC::RequestParser rp{ctx}; 99 *out_service =
265 auto type{rp.PopEnum<TimeType>()}; 100 std::make_shared<TimeZoneService>(m_system, m_time->m_standard_steady_clock, m_time_zone,
266 101 m_setup_info.can_write_timezone_device_location);
267 ClockSnapshot snapshot{}; 102 R_SUCCEED();
268 auto res = GetClockSnapshot(snapshot, type);
269
270 ctx.WriteBuffer(snapshot);
271
272 IPC::ResponseBuilder rb{ctx, 2};
273 rb.Push(res);
274} 103}
275 104
276void StaticService::Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx) { 105Result StaticService::GetStandardLocalSystemClock(OutInterface<SystemClock> out_service) {
277 LOG_DEBUG(Service_Time, "called."); 106 LOG_DEBUG(Service_Time, "called.");
278 107
279 IPC::RequestParser rp{ctx}; 108 *out_service = std::make_shared<SystemClock>(m_system, m_local_system_clock,
280 auto clock_type{rp.PopEnum<TimeType>()}; 109 m_setup_info.can_write_local_clock,
281 [[maybe_unused]] auto alignment{rp.Pop<u32>()}; 110 m_setup_info.can_write_uninitialized_clock);
282 auto user_context{rp.PopRaw<SystemClockContext>()}; 111 R_SUCCEED();
283 auto network_context{rp.PopRaw<SystemClockContext>()};
284
285 ClockSnapshot snapshot{};
286 auto res =
287 GetClockSnapshotFromSystemClockContext(snapshot, user_context, network_context, clock_type);
288
289 ctx.WriteBuffer(snapshot);
290
291 IPC::ResponseBuilder rb{ctx, 2};
292 rb.Push(res);
293} 112}
294 113
295void StaticService::Handle_CalculateStandardUserSystemClockDifferenceByUser( 114Result StaticService::GetEphemeralNetworkSystemClock(OutInterface<SystemClock> out_service) {
296 HLERequestContext& ctx) {
297 LOG_DEBUG(Service_Time, "called."); 115 LOG_DEBUG(Service_Time, "called.");
298 116
299 ClockSnapshot a{}; 117 *out_service = std::make_shared<SystemClock>(m_system, m_ephemeral_network_clock,
300 ClockSnapshot b{}; 118 m_setup_info.can_write_network_clock,
301 119 m_setup_info.can_write_uninitialized_clock);
302 auto a_buffer{ctx.ReadBuffer(0)}; 120 R_SUCCEED();
303 auto b_buffer{ctx.ReadBuffer(1)};
304
305 std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot));
306 std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot));
307
308 s64 difference{};
309 auto res = CalculateStandardUserSystemClockDifferenceByUser(difference, a, b);
310
311 IPC::ResponseBuilder rb{ctx, 4};
312 rb.Push(res);
313 rb.Push(difference);
314} 121}
315 122
316void StaticService::Handle_CalculateSpanBetween(HLERequestContext& ctx) { 123Result StaticService::GetSharedMemoryNativeHandle(
124 OutCopyHandle<Kernel::KSharedMemory> out_shared_memory) {
317 LOG_DEBUG(Service_Time, "called."); 125 LOG_DEBUG(Service_Time, "called.");
318 126
319 ClockSnapshot a{}; 127 *out_shared_memory = &m_shared_memory.GetKSharedMemory();
320 ClockSnapshot b{};
321
322 auto a_buffer{ctx.ReadBuffer(0)};
323 auto b_buffer{ctx.ReadBuffer(1)};
324
325 std::memcpy(&a, a_buffer.data(), sizeof(ClockSnapshot));
326 std::memcpy(&b, b_buffer.data(), sizeof(ClockSnapshot));
327
328 s64 time{};
329 auto res = CalculateSpanBetween(time, a, b);
330
331 IPC::ResponseBuilder rb{ctx, 4};
332 rb.Push(res);
333 rb.Push(time);
334}
335
336// =============================== Implementations ===========================
337
338Result StaticService::GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service) {
339 out_service = std::make_shared<SystemClock>(m_system, m_user_system_clock,
340 m_setup_info.can_write_user_clock,
341 m_setup_info.can_write_uninitialized_clock);
342 R_SUCCEED(); 128 R_SUCCEED();
343} 129}
344 130
345Result StaticService::GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) { 131Result StaticService::SetStandardSteadyClockInternalOffset(s64 offset_ns) {
346 out_service = std::make_shared<SystemClock>(m_system, m_network_system_clock, 132 LOG_DEBUG(Service_Time, "called. This function is not implemented!");
347 m_setup_info.can_write_network_clock,
348 m_setup_info.can_write_uninitialized_clock);
349 R_SUCCEED();
350}
351 133
352Result StaticService::GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service) { 134 R_UNLESS(m_setup_info.can_write_steady_clock, ResultPermissionDenied);
353 out_service =
354 std::make_shared<SteadyClock>(m_system, m_time, m_setup_info.can_write_steady_clock,
355 m_setup_info.can_write_uninitialized_clock);
356 R_SUCCEED();
357}
358 135
359Result StaticService::GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service) { 136 R_RETURN(ResultNotImplemented);
360 out_service =
361 std::make_shared<TimeZoneService>(m_system, m_time->m_standard_steady_clock, m_time_zone,
362 m_setup_info.can_write_timezone_device_location);
363 R_SUCCEED();
364} 137}
365 138
366Result StaticService::GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service) { 139Result StaticService::GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value) {
367 out_service = std::make_shared<SystemClock>(m_system, m_local_system_clock, 140 LOG_DEBUG(Service_Time, "called. This function is not implemented!");
368 m_setup_info.can_write_local_clock,
369 m_setup_info.can_write_uninitialized_clock);
370 R_SUCCEED();
371}
372 141
373Result StaticService::GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service) { 142 R_RETURN(ResultNotImplemented);
374 out_service = std::make_shared<SystemClock>(m_system, m_ephemeral_network_clock,
375 m_setup_info.can_write_network_clock,
376 m_setup_info.can_write_uninitialized_clock);
377 R_SUCCEED();
378} 143}
379 144
380Result StaticService::GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory) { 145Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(
381 *out_shared_memory = &m_shared_memory.GetKSharedMemory(); 146 Out<bool> out_is_enabled) {
382 R_SUCCEED(); 147 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_enabled={}", *out_is_enabled); });
383}
384 148
385Result StaticService::IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled) {
386 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); 149 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
387 150
388 out_is_enabled = m_user_system_clock.GetAutomaticCorrection(); 151 *out_is_enabled = m_user_system_clock.GetAutomaticCorrection();
152
389 R_SUCCEED(); 153 R_SUCCEED();
390} 154}
391 155
392Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled( 156Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
393 bool automatic_correction) { 157 bool automatic_correction) {
158 LOG_DEBUG(Service_Time, "called. automatic_correction={}", automatic_correction);
159
394 R_UNLESS(m_user_system_clock.IsInitialized() && m_time->m_standard_steady_clock.IsInitialized(), 160 R_UNLESS(m_user_system_clock.IsInitialized() && m_time->m_standard_steady_clock.IsInitialized(),
395 ResultClockUninitialized); 161 ResultClockUninitialized);
396 R_UNLESS(m_setup_info.can_write_user_clock, ResultPermissionDenied); 162 R_UNLESS(m_setup_info.can_write_user_clock, ResultPermissionDenied);
@@ -407,22 +173,35 @@ Result StaticService::SetStandardUserSystemClockAutomaticCorrectionEnabled(
407 R_SUCCEED(); 173 R_SUCCEED();
408} 174}
409 175
410Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient) { 176Result StaticService::GetStandardUserSystemClockInitialYear(Out<s32> out_year) {
411 out_is_sufficient = m_network_system_clock.IsAccuracySufficient(); 177 LOG_DEBUG(Service_Time, "called. This function is not implemented!");
178
179 R_RETURN(ResultNotImplemented);
180}
181
182Result StaticService::IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient) {
183 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_sufficient={}", *out_is_sufficient); });
184
185 *out_is_sufficient = m_network_system_clock.IsAccuracySufficient();
186
412 R_SUCCEED(); 187 R_SUCCEED();
413} 188}
414 189
415Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 190Result StaticService::GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
416 SteadyClockTimePoint& out_time_point) { 191 Out<SteadyClockTimePoint> out_time_point) {
192 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); });
193
417 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized); 194 R_UNLESS(m_user_system_clock.IsInitialized(), ResultClockUninitialized);
418 195
419 m_user_system_clock.GetTimePoint(out_time_point); 196 m_user_system_clock.GetTimePoint(*out_time_point);
420 197
421 R_SUCCEED(); 198 R_SUCCEED();
422} 199}
423 200
424Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(s64& out_time, 201Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(Out<s64> out_time,
425 SystemClockContext& context) { 202 SystemClockContext& context) {
203 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. context={} out_time={}", context, *out_time); });
204
426 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized); 205 R_UNLESS(m_time->m_standard_steady_clock.IsInitialized(), ResultClockUninitialized);
427 206
428 SteadyClockTimePoint time_point{}; 207 SteadyClockTimePoint time_point{};
@@ -433,12 +212,16 @@ Result StaticService::CalculateMonotonicSystemClockBaseTimePoint(s64& out_time,
433 auto one_second_ns{ 212 auto one_second_ns{
434 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()}; 213 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(1)).count()};
435 auto ticks{m_system.CoreTiming().GetClockTicks()}; 214 auto ticks{m_system.CoreTiming().GetClockTicks()};
436 auto current_time{ConvertToTimeSpan(ticks).count()}; 215 auto current_time_ns{ConvertToTimeSpan(ticks).count()};
437 out_time = ((context.offset + time_point.time_point) - (current_time / one_second_ns)); 216 *out_time = ((context.offset + time_point.time_point) - (current_time_ns / one_second_ns));
217
438 R_SUCCEED(); 218 R_SUCCEED();
439} 219}
440 220
441Result StaticService::GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type) { 221Result StaticService::GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type) {
222 SCOPE_EXIT(
223 { LOG_DEBUG(Service_Time, "called. type={} out_snapshot={}", type, *out_snapshot); });
224
442 SystemClockContext user_context{}; 225 SystemClockContext user_context{};
443 R_TRY(m_user_system_clock.GetContext(user_context)); 226 R_TRY(m_user_system_clock.GetContext(user_context));
444 227
@@ -448,53 +231,101 @@ Result StaticService::GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType typ
448 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); 231 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
449} 232}
450 233
451Result StaticService::GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot, 234Result StaticService::GetClockSnapshotFromSystemClockContext(TimeType type,
235 OutClockSnapshot out_snapshot,
452 SystemClockContext& user_context, 236 SystemClockContext& user_context,
453 SystemClockContext& network_context, 237 SystemClockContext& network_context) {
454 TimeType type) { 238 SCOPE_EXIT({
239 LOG_DEBUG(Service_Time,
240 "called. type={} user_context={} network_context={} out_snapshot={}", type,
241 user_context, network_context, *out_snapshot);
242 });
243
455 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type)); 244 R_RETURN(GetClockSnapshotImpl(out_snapshot, user_context, network_context, type));
456} 245}
457 246
458Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, 247Result StaticService::CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
459 ClockSnapshot& a, 248 InClockSnapshot a,
460 ClockSnapshot& b) { 249 InClockSnapshot b) {
250 SCOPE_EXIT({
251 LOG_DEBUG(Service_Time, "called. a={} b={} out_difference={}", *a, *b, *out_difference);
252 });
253
461 auto diff_s = 254 auto diff_s =
462 std::chrono::seconds(b.user_context.offset) - std::chrono::seconds(a.user_context.offset); 255 std::chrono::seconds(b->user_context.offset) - std::chrono::seconds(a->user_context.offset);
463 256
464 if (a.user_context == b.user_context || 257 if (a->user_context == b->user_context ||
465 !a.user_context.steady_time_point.IdMatches(b.user_context.steady_time_point)) { 258 !a->user_context.steady_time_point.IdMatches(b->user_context.steady_time_point)) {
466 out_time = 0; 259 *out_difference = 0;
467 R_SUCCEED(); 260 R_SUCCEED();
468 } 261 }
469 262
470 if (!a.is_automatic_correction_enabled || !b.is_automatic_correction_enabled) { 263 if (!a->is_automatic_correction_enabled || !b->is_automatic_correction_enabled) {
471 out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count(); 264 *out_difference = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count();
472 R_SUCCEED(); 265 R_SUCCEED();
473 } 266 }
474 267
475 if (a.network_context.steady_time_point.IdMatches(a.steady_clock_time_point) || 268 if (a->network_context.steady_time_point.IdMatches(a->steady_clock_time_point) ||
476 b.network_context.steady_time_point.IdMatches(b.steady_clock_time_point)) { 269 b->network_context.steady_time_point.IdMatches(b->steady_clock_time_point)) {
477 out_time = 0; 270 *out_difference = 0;
478 R_SUCCEED(); 271 R_SUCCEED();
479 } 272 }
480 273
481 out_time = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count(); 274 *out_difference = std::chrono::duration_cast<std::chrono::nanoseconds>(diff_s).count();
482 R_SUCCEED(); 275 R_SUCCEED();
483} 276}
484 277
485Result StaticService::CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b) { 278Result StaticService::CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a,
279 InClockSnapshot b) {
280 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. a={} b={} out_time={}", *a, *b, *out_time); });
281
486 s64 time_s{}; 282 s64 time_s{};
487 auto res = 283 auto res =
488 GetSpanBetweenTimePoints(&time_s, a.steady_clock_time_point, b.steady_clock_time_point); 284 GetSpanBetweenTimePoints(&time_s, a->steady_clock_time_point, b->steady_clock_time_point);
489 285
490 if (res != ResultSuccess) { 286 if (res != ResultSuccess) {
491 R_UNLESS(a.network_time != 0 && b.network_time != 0, ResultTimeNotFound); 287 R_UNLESS(a->network_time != 0 && b->network_time != 0, ResultTimeNotFound);
492 time_s = b.network_time - a.network_time; 288 time_s = b->network_time - a->network_time;
493 } 289 }
494 290
495 out_time = 291 *out_time =
496 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(time_s)).count(); 292 std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(time_s)).count();
497 R_SUCCEED(); 293 R_SUCCEED();
498} 294}
499 295
296Result StaticService::GetClockSnapshotImpl(OutClockSnapshot out_snapshot,
297 SystemClockContext& user_context,
298 SystemClockContext& network_context, TimeType type) {
299 out_snapshot->user_context = user_context;
300 out_snapshot->network_context = network_context;
301
302 R_TRY(
303 m_time->m_standard_steady_clock.GetCurrentTimePoint(out_snapshot->steady_clock_time_point));
304
305 out_snapshot->is_automatic_correction_enabled = m_user_system_clock.GetAutomaticCorrection();
306
307 R_TRY(m_time_zone.GetLocationName(out_snapshot->location_name));
308
309 R_TRY(GetTimeFromTimePointAndContext(&out_snapshot->user_time,
310 out_snapshot->steady_clock_time_point,
311 out_snapshot->user_context));
312
313 R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot->user_calendar_time,
314 out_snapshot->user_calendar_additional_time,
315 out_snapshot->user_time));
316
317 if (GetTimeFromTimePointAndContext(&out_snapshot->network_time,
318 out_snapshot->steady_clock_time_point,
319 out_snapshot->network_context) != ResultSuccess) {
320 out_snapshot->network_time = 0;
321 }
322
323 R_TRY(m_time_zone.ToCalendarTimeWithMyRule(out_snapshot->network_calendar_time,
324 out_snapshot->network_calendar_additional_time,
325 out_snapshot->network_time));
326 out_snapshot->type = type;
327 out_snapshot->unk_CE = 0;
328 R_SUCCEED();
329}
330
500} // namespace Service::PSC::Time 331} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/static.h b/src/core/hle/service/psc/time/static.h
index 498cd5ab5..120bab259 100644
--- a/src/core/hle/service/psc/time/static.h
+++ b/src/core/hle/service/psc/time/static.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/common.h" 8#include "core/hle/service/psc/time/common.h"
8#include "core/hle/service/server_manager.h" 9#include "core/hle/service/server_manager.h"
@@ -29,58 +30,44 @@ class EphemeralNetworkSystemClockCore;
29class SharedMemory; 30class SharedMemory;
30 31
31class StaticService final : public ServiceFramework<StaticService> { 32class StaticService final : public ServiceFramework<StaticService> {
33 using InClockSnapshot = InLargeData<ClockSnapshot, BufferAttr_HipcPointer>;
34 using OutClockSnapshot = OutLargeData<ClockSnapshot, BufferAttr_HipcPointer>;
35
32public: 36public:
33 explicit StaticService(Core::System& system, StaticServiceSetupInfo setup_info, 37 explicit StaticService(Core::System& system, StaticServiceSetupInfo setup_info,
34 std::shared_ptr<TimeManager> time, const char* name); 38 std::shared_ptr<TimeManager> time, const char* name);
35 39
36 ~StaticService() override = default; 40 ~StaticService() override = default;
37 41
38 Result GetStandardUserSystemClock(std::shared_ptr<SystemClock>& out_service); 42 Result GetStandardUserSystemClock(OutInterface<SystemClock> out_service);
39 Result GetStandardNetworkSystemClock(std::shared_ptr<SystemClock>& out_service); 43 Result GetStandardNetworkSystemClock(OutInterface<SystemClock> out_service);
40 Result GetStandardSteadyClock(std::shared_ptr<SteadyClock>& out_service); 44 Result GetStandardSteadyClock(OutInterface<SteadyClock> out_service);
41 Result GetTimeZoneService(std::shared_ptr<TimeZoneService>& out_service); 45 Result GetTimeZoneService(OutInterface<TimeZoneService> out_service);
42 Result GetStandardLocalSystemClock(std::shared_ptr<SystemClock>& out_service); 46 Result GetStandardLocalSystemClock(OutInterface<SystemClock> out_service);
43 Result GetEphemeralNetworkSystemClock(std::shared_ptr<SystemClock>& out_service); 47 Result GetEphemeralNetworkSystemClock(OutInterface<SystemClock> out_service);
44 Result GetSharedMemoryNativeHandle(Kernel::KSharedMemory** out_shared_memory); 48 Result GetSharedMemoryNativeHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory);
45 Result IsStandardUserSystemClockAutomaticCorrectionEnabled(bool& out_is_enabled); 49 Result SetStandardSteadyClockInternalOffset(s64 offset_ns);
50 Result GetStandardSteadyClockRtcValue(Out<s64> out_rtc_value);
51 Result IsStandardUserSystemClockAutomaticCorrectionEnabled(Out<bool> out_is_enabled);
46 Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction); 52 Result SetStandardUserSystemClockAutomaticCorrectionEnabled(bool automatic_correction);
47 Result IsStandardNetworkSystemClockAccuracySufficient(bool& out_is_sufficient); 53 Result GetStandardUserSystemClockInitialYear(Out<s32> out_year);
54 Result IsStandardNetworkSystemClockAccuracySufficient(Out<bool> out_is_sufficient);
48 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime( 55 Result GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(
49 SteadyClockTimePoint& out_time_point); 56 Out<SteadyClockTimePoint> out_time_point);
50 Result CalculateMonotonicSystemClockBaseTimePoint(s64& out_time, SystemClockContext& context); 57 Result CalculateMonotonicSystemClockBaseTimePoint(Out<s64> out_time,
51 Result GetClockSnapshot(ClockSnapshot& out_snapshot, TimeType type); 58 SystemClockContext& context);
52 Result GetClockSnapshotFromSystemClockContext(ClockSnapshot& out_snapshot, 59 Result GetClockSnapshot(OutClockSnapshot out_snapshot, TimeType type);
60 Result GetClockSnapshotFromSystemClockContext(TimeType type, OutClockSnapshot out_snapshot,
53 SystemClockContext& user_context, 61 SystemClockContext& user_context,
54 SystemClockContext& network_context, 62 SystemClockContext& network_context);
55 TimeType type); 63 Result CalculateStandardUserSystemClockDifferenceByUser(Out<s64> out_difference,
56 Result CalculateStandardUserSystemClockDifferenceByUser(s64& out_time, ClockSnapshot& a, 64 InClockSnapshot a, InClockSnapshot b);
57 ClockSnapshot& b); 65 Result CalculateSpanBetween(Out<s64> out_time, InClockSnapshot a, InClockSnapshot b);
58 Result CalculateSpanBetween(s64& out_time, ClockSnapshot& a, ClockSnapshot& b);
59 66
60private: 67private:
61 Result GetClockSnapshotImpl(ClockSnapshot& out_snapshot, SystemClockContext& user_context, 68 Result GetClockSnapshotImpl(OutClockSnapshot out_snapshot, SystemClockContext& user_context,
62 SystemClockContext& network_context, TimeType type); 69 SystemClockContext& network_context, TimeType type);
63 70
64 void Handle_GetStandardUserSystemClock(HLERequestContext& ctx);
65 void Handle_GetStandardNetworkSystemClock(HLERequestContext& ctx);
66 void Handle_GetStandardSteadyClock(HLERequestContext& ctx);
67 void Handle_GetTimeZoneService(HLERequestContext& ctx);
68 void Handle_GetStandardLocalSystemClock(HLERequestContext& ctx);
69 void Handle_GetEphemeralNetworkSystemClock(HLERequestContext& ctx);
70 void Handle_GetSharedMemoryNativeHandle(HLERequestContext& ctx);
71 void Handle_SetStandardSteadyClockInternalOffset(HLERequestContext& ctx);
72 void Handle_GetStandardSteadyClockRtcValue(HLERequestContext& ctx);
73 void Handle_IsStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
74 void Handle_SetStandardUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
75 void Handle_GetStandardUserSystemClockInitialYear(HLERequestContext& ctx);
76 void Handle_IsStandardNetworkSystemClockAccuracySufficient(HLERequestContext& ctx);
77 void Handle_GetStandardUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx);
78 void Handle_CalculateMonotonicSystemClockBaseTimePoint(HLERequestContext& ctx);
79 void Handle_GetClockSnapshot(HLERequestContext& ctx);
80 void Handle_GetClockSnapshotFromSystemClockContext(HLERequestContext& ctx);
81 void Handle_CalculateStandardUserSystemClockDifferenceByUser(HLERequestContext& ctx);
82 void Handle_CalculateSpanBetween(HLERequestContext& ctx);
83
84 Core::System& m_system; 71 Core::System& m_system;
85 StaticServiceSetupInfo m_setup_info; 72 StaticServiceSetupInfo m_setup_info;
86 std::shared_ptr<TimeManager> m_time; 73 std::shared_ptr<TimeManager> m_time;
diff --git a/src/core/hle/service/psc/time/steady_clock.cpp b/src/core/hle/service/psc/time/steady_clock.cpp
index 1ed5c7679..948610a2b 100644
--- a/src/core/hle/service/psc/time/steady_clock.cpp
+++ b/src/core/hle/service/psc/time/steady_clock.cpp
@@ -1,7 +1,9 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/scope_exit.h"
4#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/time/steady_clock.h" 7#include "core/hle/service/psc/time/steady_clock.h"
6 8
7namespace Service::PSC::Time { 9namespace Service::PSC::Time {
@@ -14,114 +16,40 @@ SteadyClock::SteadyClock(Core::System& system_, std::shared_ptr<TimeManager> man
14 can_write_uninitialized_clock} { 16 can_write_uninitialized_clock} {
15 // clang-format off 17 // clang-format off
16 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
17 {0, &SteadyClock::Handle_GetCurrentTimePoint, "GetCurrentTimePoint"}, 19 {0, D<&SteadyClock::GetCurrentTimePoint>, "GetCurrentTimePoint"},
18 {2, &SteadyClock::Handle_GetTestOffset, "GetTestOffset"}, 20 {2, D<&SteadyClock::GetTestOffset>, "GetTestOffset"},
19 {3, &SteadyClock::Handle_SetTestOffset, "SetTestOffset"}, 21 {3, D<&SteadyClock::SetTestOffset>, "SetTestOffset"},
20 {100, &SteadyClock::Handle_GetRtcValue, "GetRtcValue"}, 22 {100, D<&SteadyClock::GetRtcValue>, "GetRtcValue"},
21 {101, &SteadyClock::Handle_IsRtcResetDetected, "IsRtcResetDetected"}, 23 {101, D<&SteadyClock::IsRtcResetDetected>, "IsRtcResetDetected"},
22 {102, &SteadyClock::Handle_GetSetupResultValue, "GetSetupResultValue"}, 24 {102, D<&SteadyClock::GetSetupResultValue>, "GetSetupResultValue"},
23 {200, &SteadyClock::Handle_GetInternalOffset, "GetInternalOffset"}, 25 {200, D<&SteadyClock::GetInternalOffset>, "GetInternalOffset"},
24 }; 26 };
25 // clang-format on 27 // clang-format on
26 RegisterHandlers(functions); 28 RegisterHandlers(functions);
27} 29}
28 30
29void SteadyClock::Handle_GetCurrentTimePoint(HLERequestContext& ctx) { 31Result SteadyClock::GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point) {
30 LOG_DEBUG(Service_Time, "called."); 32 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time_point={}", *out_time_point); });
31 33
32 SteadyClockTimePoint time_point{};
33 auto res = GetCurrentTimePoint(time_point);
34
35 IPC::ResponseBuilder rb{ctx, 2 + sizeof(SteadyClockTimePoint) / sizeof(u32)};
36 rb.Push(res);
37 rb.PushRaw<SteadyClockTimePoint>(time_point);
38}
39
40void SteadyClock::Handle_GetTestOffset(HLERequestContext& ctx) {
41 LOG_DEBUG(Service_Time, "called.");
42
43 s64 test_offset{};
44 auto res = GetTestOffset(test_offset);
45
46 IPC::ResponseBuilder rb{ctx, 4};
47 rb.Push(res);
48 rb.Push(test_offset);
49}
50
51void SteadyClock::Handle_SetTestOffset(HLERequestContext& ctx) {
52 LOG_DEBUG(Service_Time, "called.");
53
54 IPC::RequestParser rp{ctx};
55 auto test_offset{rp.Pop<s64>()};
56
57 auto res = SetTestOffset(test_offset);
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(res);
61}
62
63void SteadyClock::Handle_GetRtcValue(HLERequestContext& ctx) {
64 LOG_DEBUG(Service_Time, "called.");
65
66 s64 rtc_value{};
67 auto res = GetRtcValue(rtc_value);
68
69 IPC::ResponseBuilder rb{ctx, 4};
70 rb.Push(res);
71 rb.Push(rtc_value);
72}
73
74void SteadyClock::Handle_IsRtcResetDetected(HLERequestContext& ctx) {
75 LOG_DEBUG(Service_Time, "called.");
76
77 bool reset_detected{false};
78 auto res = IsRtcResetDetected(reset_detected);
79
80 IPC::ResponseBuilder rb{ctx, 3};
81 rb.Push(res);
82 rb.Push(reset_detected);
83}
84
85void SteadyClock::Handle_GetSetupResultValue(HLERequestContext& ctx) {
86 LOG_DEBUG(Service_Time, "called.");
87
88 Result result_value{ResultSuccess};
89 auto res = GetSetupResultValue(result_value);
90
91 IPC::ResponseBuilder rb{ctx, 3};
92 rb.Push(res);
93 rb.Push(result_value);
94}
95
96void SteadyClock::Handle_GetInternalOffset(HLERequestContext& ctx) {
97 LOG_DEBUG(Service_Time, "called.");
98
99 s64 internal_offset{};
100 auto res = GetInternalOffset(internal_offset);
101
102 IPC::ResponseBuilder rb{ctx, 4};
103 rb.Push(res);
104 rb.Push(internal_offset);
105}
106
107// =============================== Implementations ===========================
108
109Result SteadyClock::GetCurrentTimePoint(SteadyClockTimePoint& out_time_point) {
110 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 34 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
111 ResultClockUninitialized); 35 ResultClockUninitialized);
112 36
113 R_RETURN(m_clock_core.GetCurrentTimePoint(out_time_point)); 37 R_RETURN(m_clock_core.GetCurrentTimePoint(*out_time_point));
114} 38}
115 39
116Result SteadyClock::GetTestOffset(s64& out_test_offset) { 40Result SteadyClock::GetTestOffset(Out<s64> out_test_offset) {
41 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_test_offset={}", *out_test_offset); });
42
117 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 43 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
118 ResultClockUninitialized); 44 ResultClockUninitialized);
119 45
120 out_test_offset = m_clock_core.GetTestOffset(); 46 *out_test_offset = m_clock_core.GetTestOffset();
121 R_SUCCEED(); 47 R_SUCCEED();
122} 48}
123 49
124Result SteadyClock::SetTestOffset(s64 test_offset) { 50Result SteadyClock::SetTestOffset(s64 test_offset) {
51 LOG_DEBUG(Service_Time, "called. test_offset={}", test_offset);
52
125 R_UNLESS(m_can_write_steady_clock, ResultPermissionDenied); 53 R_UNLESS(m_can_write_steady_clock, ResultPermissionDenied);
126 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 54 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
127 ResultClockUninitialized); 55 ResultClockUninitialized);
@@ -130,34 +58,43 @@ Result SteadyClock::SetTestOffset(s64 test_offset) {
130 R_SUCCEED(); 58 R_SUCCEED();
131} 59}
132 60
133Result SteadyClock::GetRtcValue(s64& out_rtc_value) { 61Result SteadyClock::GetRtcValue(Out<s64> out_rtc_value) {
62 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rtc_value={}", *out_rtc_value); });
63
134 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 64 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
135 ResultClockUninitialized); 65 ResultClockUninitialized);
136 66
137 R_RETURN(m_clock_core.GetRtcValue(out_rtc_value)); 67 R_RETURN(m_clock_core.GetRtcValue(*out_rtc_value));
138} 68}
139 69
140Result SteadyClock::IsRtcResetDetected(bool& out_is_detected) { 70Result SteadyClock::IsRtcResetDetected(Out<bool> out_is_detected) {
71 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_is_detected={}", *out_is_detected); });
72
141 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 73 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
142 ResultClockUninitialized); 74 ResultClockUninitialized);
143 75
144 out_is_detected = m_clock_core.IsResetDetected(); 76 *out_is_detected = m_clock_core.IsResetDetected();
145 R_SUCCEED(); 77 R_SUCCEED();
146} 78}
147 79
148Result SteadyClock::GetSetupResultValue(Result& out_result) { 80Result SteadyClock::GetSetupResultValue(Out<Result> out_result) {
81 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_result=0x{:X}", out_result->raw); });
82
149 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 83 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
150 ResultClockUninitialized); 84 ResultClockUninitialized);
151 85
152 out_result = m_clock_core.GetSetupResultValue(); 86 *out_result = m_clock_core.GetSetupResultValue();
153 R_SUCCEED(); 87 R_SUCCEED();
154} 88}
155 89
156Result SteadyClock::GetInternalOffset(s64& out_internal_offset) { 90Result SteadyClock::GetInternalOffset(Out<s64> out_internal_offset) {
91 SCOPE_EXIT(
92 { LOG_DEBUG(Service_Time, "called. out_internal_offset={}", *out_internal_offset); });
93
157 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 94 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
158 ResultClockUninitialized); 95 ResultClockUninitialized);
159 96
160 out_internal_offset = m_clock_core.GetInternalOffset(); 97 *out_internal_offset = m_clock_core.GetInternalOffset();
161 R_SUCCEED(); 98 R_SUCCEED();
162} 99}
163 100
diff --git a/src/core/hle/service/psc/time/steady_clock.h b/src/core/hle/service/psc/time/steady_clock.h
index 115e9b138..025d758a6 100644
--- a/src/core/hle/service/psc/time/steady_clock.h
+++ b/src/core/hle/service/psc/time/steady_clock.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/common.h" 8#include "core/hle/service/psc/time/common.h"
8#include "core/hle/service/psc/time/manager.h" 9#include "core/hle/service/psc/time/manager.h"
@@ -22,23 +23,15 @@ public:
22 23
23 ~SteadyClock() override = default; 24 ~SteadyClock() override = default;
24 25
25 Result GetCurrentTimePoint(SteadyClockTimePoint& out_time_point); 26 Result GetCurrentTimePoint(Out<SteadyClockTimePoint> out_time_point);
26 Result GetTestOffset(s64& out_test_offset); 27 Result GetTestOffset(Out<s64> out_test_offset);
27 Result SetTestOffset(s64 test_offset); 28 Result SetTestOffset(s64 test_offset);
28 Result GetRtcValue(s64& out_rtc_value); 29 Result GetRtcValue(Out<s64> out_rtc_value);
29 Result IsRtcResetDetected(bool& out_is_detected); 30 Result IsRtcResetDetected(Out<bool> out_is_detected);
30 Result GetSetupResultValue(Result& out_result); 31 Result GetSetupResultValue(Out<Result> out_result);
31 Result GetInternalOffset(s64& out_internal_offset); 32 Result GetInternalOffset(Out<s64> out_internal_offset);
32 33
33private: 34private:
34 void Handle_GetCurrentTimePoint(HLERequestContext& ctx);
35 void Handle_GetTestOffset(HLERequestContext& ctx);
36 void Handle_SetTestOffset(HLERequestContext& ctx);
37 void Handle_GetRtcValue(HLERequestContext& ctx);
38 void Handle_IsRtcResetDetected(HLERequestContext& ctx);
39 void Handle_GetSetupResultValue(HLERequestContext& ctx);
40 void Handle_GetInternalOffset(HLERequestContext& ctx);
41
42 Core::System& m_system; 35 Core::System& m_system;
43 36
44 StandardSteadyClockCore& m_clock_core; 37 StandardSteadyClockCore& m_clock_core;
diff --git a/src/core/hle/service/psc/time/system_clock.cpp b/src/core/hle/service/psc/time/system_clock.cpp
index 13d2f1d11..0695502d5 100644
--- a/src/core/hle/service/psc/time/system_clock.cpp
+++ b/src/core/hle/service/psc/time/system_clock.cpp
@@ -1,7 +1,9 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/scope_exit.h"
4#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/psc/time/system_clock.h" 7#include "core/hle/service/psc/time/system_clock.h"
6 8
7namespace Service::PSC::Time { 9namespace Service::PSC::Time {
@@ -13,83 +15,28 @@ SystemClock::SystemClock(Core::System& system_, SystemClockCore& clock_core, boo
13 can_write_uninitialized_clock} { 15 can_write_uninitialized_clock} {
14 // clang-format off 16 // clang-format off
15 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
16 {0, &SystemClock::Handle_GetCurrentTime, "GetCurrentTime"}, 18 {0, D<&SystemClock::GetCurrentTime>, "GetCurrentTime"},
17 {1, &SystemClock::Handle_SetCurrentTime, "SetCurrentTime"}, 19 {1, D<&SystemClock::SetCurrentTime>, "SetCurrentTime"},
18 {2, &SystemClock::Handle_GetSystemClockContext, "GetSystemClockContext"}, 20 {2, D<&SystemClock::GetSystemClockContext>, "GetSystemClockContext"},
19 {3, &SystemClock::Handle_SetSystemClockContext, "SetSystemClockContext"}, 21 {3, D<&SystemClock::SetSystemClockContext>, "SetSystemClockContext"},
20 {4, &SystemClock::Handle_GetOperationEventReadableHandle, "GetOperationEventReadableHandle"}, 22 {4, D<&SystemClock::GetOperationEventReadableHandle>, "GetOperationEventReadableHandle"},
21 }; 23 };
22 // clang-format on 24 // clang-format on
23 RegisterHandlers(functions); 25 RegisterHandlers(functions);
24} 26}
25 27
26void SystemClock::Handle_GetCurrentTime(HLERequestContext& ctx) { 28Result SystemClock::GetCurrentTime(Out<s64> out_time) {
27 LOG_DEBUG(Service_Time, "called."); 29 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_time={}", *out_time); });
28
29 s64 time{};
30 auto res = GetCurrentTime(time);
31
32 IPC::ResponseBuilder rb{ctx, 4};
33 rb.Push(res);
34 rb.Push<s64>(time);
35}
36
37void SystemClock::Handle_SetCurrentTime(HLERequestContext& ctx) {
38 LOG_DEBUG(Service_Time, "called.");
39
40 IPC::RequestParser rp{ctx};
41 auto time{rp.Pop<s64>()};
42
43 auto res = SetCurrentTime(time);
44
45 IPC::ResponseBuilder rb{ctx, 2};
46 rb.Push(res);
47}
48
49void SystemClock::Handle_GetSystemClockContext(HLERequestContext& ctx) {
50 LOG_DEBUG(Service_Time, "called.");
51
52 SystemClockContext context{};
53 auto res = GetSystemClockContext(context);
54
55 IPC::ResponseBuilder rb{ctx, 2 + sizeof(SystemClockContext) / sizeof(u32)};
56 rb.Push(res);
57 rb.PushRaw<SystemClockContext>(context);
58}
59
60void SystemClock::Handle_SetSystemClockContext(HLERequestContext& ctx) {
61 LOG_DEBUG(Service_Time, "called.");
62
63 IPC::RequestParser rp{ctx};
64 auto context{rp.PopRaw<SystemClockContext>()};
65
66 auto res = SetSystemClockContext(context);
67
68 IPC::ResponseBuilder rb{ctx, 2};
69 rb.Push(res);
70}
71
72void SystemClock::Handle_GetOperationEventReadableHandle(HLERequestContext& ctx) {
73 LOG_DEBUG(Service_Time, "called.");
74
75 Kernel::KEvent* event{};
76 auto res = GetOperationEventReadableHandle(&event);
77 30
78 IPC::ResponseBuilder rb{ctx, 2, 1};
79 rb.Push(res);
80 rb.PushCopyObjects(event->GetReadableEvent());
81}
82
83// =============================== Implementations ===========================
84
85Result SystemClock::GetCurrentTime(s64& out_time) {
86 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 31 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
87 ResultClockUninitialized); 32 ResultClockUninitialized);
88 33
89 R_RETURN(m_clock_core.GetCurrentTime(&out_time)); 34 R_RETURN(m_clock_core.GetCurrentTime(out_time.Get()));
90} 35}
91 36
92Result SystemClock::SetCurrentTime(s64 time) { 37Result SystemClock::SetCurrentTime(s64 time) {
38 LOG_DEBUG(Service_Time, "called. time={}", time);
39
93 R_UNLESS(m_can_write_clock, ResultPermissionDenied); 40 R_UNLESS(m_can_write_clock, ResultPermissionDenied);
94 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 41 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
95 ResultClockUninitialized); 42 ResultClockUninitialized);
@@ -97,14 +44,18 @@ Result SystemClock::SetCurrentTime(s64 time) {
97 R_RETURN(m_clock_core.SetCurrentTime(time)); 44 R_RETURN(m_clock_core.SetCurrentTime(time));
98} 45}
99 46
100Result SystemClock::GetSystemClockContext(SystemClockContext& out_context) { 47Result SystemClock::GetSystemClockContext(Out<SystemClockContext> out_context) {
48 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_context={}", *out_context); });
49
101 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 50 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
102 ResultClockUninitialized); 51 ResultClockUninitialized);
103 52
104 R_RETURN(m_clock_core.GetContext(out_context)); 53 R_RETURN(m_clock_core.GetContext(*out_context));
105} 54}
106 55
107Result SystemClock::SetSystemClockContext(SystemClockContext& context) { 56Result SystemClock::SetSystemClockContext(SystemClockContext& context) {
57 LOG_DEBUG(Service_Time, "called. context={}", context);
58
108 R_UNLESS(m_can_write_clock, ResultPermissionDenied); 59 R_UNLESS(m_can_write_clock, ResultPermissionDenied);
109 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(), 60 R_UNLESS(m_can_write_uninitialized_clock || m_clock_core.IsInitialized(),
110 ResultClockUninitialized); 61 ResultClockUninitialized);
@@ -112,7 +63,10 @@ Result SystemClock::SetSystemClockContext(SystemClockContext& context) {
112 R_RETURN(m_clock_core.SetContextAndWrite(context)); 63 R_RETURN(m_clock_core.SetContextAndWrite(context));
113} 64}
114 65
115Result SystemClock::GetOperationEventReadableHandle(Kernel::KEvent** out_event) { 66Result SystemClock::GetOperationEventReadableHandle(
67 OutCopyHandle<Kernel::KReadableEvent> out_event) {
68 LOG_DEBUG(Service_Time, "called.");
69
116 if (!m_operation_event) { 70 if (!m_operation_event) {
117 m_operation_event = std::make_unique<OperationEvent>(m_system); 71 m_operation_event = std::make_unique<OperationEvent>(m_system);
118 R_UNLESS(m_operation_event != nullptr, ResultFailed); 72 R_UNLESS(m_operation_event != nullptr, ResultFailed);
@@ -120,7 +74,7 @@ Result SystemClock::GetOperationEventReadableHandle(Kernel::KEvent** out_event)
120 m_clock_core.LinkOperationEvent(*m_operation_event); 74 m_clock_core.LinkOperationEvent(*m_operation_event);
121 } 75 }
122 76
123 *out_event = m_operation_event->m_event; 77 *out_event = &m_operation_event->m_event->GetReadableEvent();
124 R_SUCCEED(); 78 R_SUCCEED();
125} 79}
126 80
diff --git a/src/core/hle/service/psc/time/system_clock.h b/src/core/hle/service/psc/time/system_clock.h
index f30027e7b..b40d73595 100644
--- a/src/core/hle/service/psc/time/system_clock.h
+++ b/src/core/hle/service/psc/time/system_clock.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/common.h" 8#include "core/hle/service/psc/time/common.h"
8#include "core/hle/service/psc/time/manager.h" 9#include "core/hle/service/psc/time/manager.h"
@@ -22,19 +23,13 @@ public:
22 23
23 ~SystemClock() override = default; 24 ~SystemClock() override = default;
24 25
25 Result GetCurrentTime(s64& out_time); 26 Result GetCurrentTime(Out<s64> out_time);
26 Result SetCurrentTime(s64 time); 27 Result SetCurrentTime(s64 time);
27 Result GetSystemClockContext(SystemClockContext& out_context); 28 Result GetSystemClockContext(Out<SystemClockContext> out_context);
28 Result SetSystemClockContext(SystemClockContext& context); 29 Result SetSystemClockContext(SystemClockContext& context);
29 Result GetOperationEventReadableHandle(Kernel::KEvent** out_event); 30 Result GetOperationEventReadableHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
30 31
31private: 32private:
32 void Handle_GetCurrentTime(HLERequestContext& ctx);
33 void Handle_SetCurrentTime(HLERequestContext& ctx);
34 void Handle_GetSystemClockContext(HLERequestContext& ctx);
35 void Handle_SetSystemClockContext(HLERequestContext& ctx);
36 void Handle_GetOperationEventReadableHandle(HLERequestContext& ctx);
37
38 Core::System& m_system; 33 Core::System& m_system;
39 34
40 SystemClockCore& m_clock_core; 35 SystemClockCore& m_clock_core;
diff --git a/src/core/hle/service/psc/time/time_zone.cpp b/src/core/hle/service/psc/time/time_zone.cpp
index cfee8f866..cc855c763 100644
--- a/src/core/hle/service/psc/time/time_zone.cpp
+++ b/src/core/hle/service/psc/time/time_zone.cpp
@@ -5,7 +5,7 @@
5 5
6namespace Service::PSC::Time { 6namespace Service::PSC::Time {
7namespace { 7namespace {
8constexpr Result ValidateRule(Tz::Rule& rule) { 8constexpr Result ValidateRule(const Tz::Rule& rule) {
9 if (rule.typecnt > static_cast<s32>(Tz::TZ_MAX_TYPES) || 9 if (rule.typecnt > static_cast<s32>(Tz::TZ_MAX_TYPES) ||
10 rule.timecnt > static_cast<s32>(Tz::TZ_MAX_TIMES) || 10 rule.timecnt > static_cast<s32>(Tz::TZ_MAX_TIMES) ||
11 rule.charcnt > static_cast<s32>(Tz::TZ_MAX_CHARS)) { 11 rule.charcnt > static_cast<s32>(Tz::TZ_MAX_CHARS)) {
@@ -26,7 +26,7 @@ constexpr Result ValidateRule(Tz::Rule& rule) {
26 R_SUCCEED(); 26 R_SUCCEED();
27} 27}
28 28
29constexpr bool GetTimeZoneTime(s64& out_time, Tz::Rule& rule, s64 time, s32 index, 29constexpr bool GetTimeZoneTime(s64& out_time, const Tz::Rule& rule, s64 time, s32 index,
30 s32 index_offset) { 30 s32 index_offset) {
31 s32 found_idx{}; 31 s32 found_idx{};
32 s32 expected_index{index + index_offset}; 32 s32 expected_index{index + index_offset};
@@ -107,7 +107,7 @@ Result TimeZone::GetTimePoint(SteadyClockTimePoint& out_time_point) {
107 107
108Result TimeZone::ToCalendarTime(CalendarTime& out_calendar_time, 108Result TimeZone::ToCalendarTime(CalendarTime& out_calendar_time,
109 CalendarAdditionalInfo& out_additional_info, s64 time, 109 CalendarAdditionalInfo& out_additional_info, s64 time,
110 Tz::Rule& rule) { 110 const Tz::Rule& rule) {
111 std::scoped_lock l{m_mutex}; 111 std::scoped_lock l{m_mutex};
112 R_RETURN(ToCalendarTimeImpl(out_calendar_time, out_additional_info, time, rule)); 112 R_RETURN(ToCalendarTimeImpl(out_calendar_time, out_additional_info, time, rule));
113} 113}
@@ -140,11 +140,11 @@ Result TimeZone::ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary)
140 R_RETURN(ParseBinaryImpl(out_rule, binary)); 140 R_RETURN(ParseBinaryImpl(out_rule, binary));
141} 141}
142 142
143Result TimeZone::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 143Result TimeZone::ToPosixTime(u32& out_count, std::span<s64> out_times, size_t out_times_max_count,
144 CalendarTime& calendar, Tz::Rule& rule) { 144 const CalendarTime& calendar, const Tz::Rule& rule) {
145 std::scoped_lock l{m_mutex}; 145 std::scoped_lock l{m_mutex};
146 146
147 auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, rule, -1); 147 auto res = ToPosixTimeImpl(out_count, out_times, out_times_max_count, calendar, rule, -1);
148 148
149 if (res != ResultSuccess) { 149 if (res != ResultSuccess) {
150 if (res == ResultTimeZoneNotFound) { 150 if (res == ResultTimeZoneNotFound) {
@@ -157,11 +157,11 @@ Result TimeZone::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 ou
157 R_RETURN(res); 157 R_RETURN(res);
158} 158}
159 159
160Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, 160Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times,
161 u32 out_times_count, CalendarTime& calendar) { 161 size_t out_times_max_count, const CalendarTime& calendar) {
162 std::scoped_lock l{m_mutex}; 162 std::scoped_lock l{m_mutex};
163 163
164 auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, m_my_rule, -1); 164 auto res = ToPosixTimeImpl(out_count, out_times, out_times_max_count, calendar, m_my_rule, -1);
165 165
166 if (res != ResultSuccess) { 166 if (res != ResultSuccess) {
167 if (res == ResultTimeZoneNotFound) { 167 if (res == ResultTimeZoneNotFound) {
@@ -183,7 +183,7 @@ Result TimeZone::ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary)
183 183
184Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time, 184Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time,
185 CalendarAdditionalInfo& out_additional_info, s64 time, 185 CalendarAdditionalInfo& out_additional_info, s64 time,
186 Tz::Rule& rule) { 186 const Tz::Rule& rule) {
187 R_TRY(ValidateRule(rule)); 187 R_TRY(ValidateRule(rule));
188 188
189 Tz::CalendarTimeInternal calendar_internal{}; 189 Tz::CalendarTimeInternal calendar_internal{};
@@ -212,20 +212,23 @@ Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time,
212 R_SUCCEED(); 212 R_SUCCEED();
213} 213}
214 214
215Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 215Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times,
216 CalendarTime& calendar, Tz::Rule& rule, s32 is_dst) { 216 size_t out_times_max_count, const CalendarTime& calendar,
217 const Tz::Rule& rule, s32 is_dst) {
217 R_TRY(ValidateRule(rule)); 218 R_TRY(ValidateRule(rule));
218 219
219 calendar.month -= 1; 220 CalendarTime local_calendar{calendar};
220 calendar.year -= 1900; 221
222 local_calendar.month -= 1;
223 local_calendar.year -= 1900;
221 224
222 Tz::CalendarTimeInternal internal{ 225 Tz::CalendarTimeInternal internal{
223 .tm_sec = calendar.second, 226 .tm_sec = local_calendar.second,
224 .tm_min = calendar.minute, 227 .tm_min = local_calendar.minute,
225 .tm_hour = calendar.hour, 228 .tm_hour = local_calendar.hour,
226 .tm_mday = calendar.day, 229 .tm_mday = local_calendar.day,
227 .tm_mon = calendar.month, 230 .tm_mon = local_calendar.month,
228 .tm_year = calendar.year, 231 .tm_year = local_calendar.year,
229 .tm_wday = 0, 232 .tm_wday = 0,
230 .tm_yday = 0, 233 .tm_yday = 0,
231 .tm_isdst = is_dst, 234 .tm_isdst = is_dst,
@@ -243,9 +246,9 @@ Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u3
243 R_RETURN(ResultTimeZoneNotFound); 246 R_RETURN(ResultTimeZoneNotFound);
244 } 247 }
245 248
246 if (internal.tm_sec != calendar.second || internal.tm_min != calendar.minute || 249 if (internal.tm_sec != local_calendar.second || internal.tm_min != local_calendar.minute ||
247 internal.tm_hour != calendar.hour || internal.tm_mday != calendar.day || 250 internal.tm_hour != local_calendar.hour || internal.tm_mday != local_calendar.day ||
248 internal.tm_mon != calendar.month || internal.tm_year != calendar.year) { 251 internal.tm_mon != local_calendar.month || internal.tm_year != local_calendar.year) {
249 R_RETURN(ResultTimeZoneNotFound); 252 R_RETURN(ResultTimeZoneNotFound);
250 } 253 }
251 254
@@ -254,7 +257,7 @@ Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u3
254 } 257 }
255 258
256 out_times[0] = time; 259 out_times[0] = time;
257 if (out_times_count < 2) { 260 if (out_times_max_count < 2) {
258 out_count = 1; 261 out_count = 1;
259 R_SUCCEED(); 262 R_SUCCEED();
260 } 263 }
diff --git a/src/core/hle/service/psc/time/time_zone.h b/src/core/hle/service/psc/time/time_zone.h
index ce2acca17..6248e45f9 100644
--- a/src/core/hle/service/psc/time/time_zone.h
+++ b/src/core/hle/service/psc/time/time_zone.h
@@ -32,23 +32,24 @@ public:
32 Result GetTimePoint(SteadyClockTimePoint& out_time_point); 32 Result GetTimePoint(SteadyClockTimePoint& out_time_point);
33 33
34 Result ToCalendarTime(CalendarTime& out_calendar_time, 34 Result ToCalendarTime(CalendarTime& out_calendar_time,
35 CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule); 35 CalendarAdditionalInfo& out_additional_info, s64 time,
36 const Tz::Rule& rule);
36 Result ToCalendarTimeWithMyRule(CalendarTime& calendar_time, 37 Result ToCalendarTimeWithMyRule(CalendarTime& calendar_time,
37 CalendarAdditionalInfo& calendar_additional, s64 time); 38 CalendarAdditionalInfo& calendar_additional, s64 time);
38 Result ParseBinary(LocationName& name, std::span<const u8> binary); 39 Result ParseBinary(LocationName& name, std::span<const u8> binary);
39 Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary); 40 Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary);
40 Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 41 Result ToPosixTime(u32& out_count, std::span<s64> out_times, size_t out_times_max_count,
41 CalendarTime& calendar, Tz::Rule& rule); 42 const CalendarTime& calendar, const Tz::Rule& rule);
42 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 43 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times,
43 CalendarTime& calendar); 44 size_t out_times_max_count, const CalendarTime& calendar);
44 45
45private: 46private:
46 Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary); 47 Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary);
47 Result ToCalendarTimeImpl(CalendarTime& out_calendar_time, 48 Result ToCalendarTimeImpl(CalendarTime& out_calendar_time,
48 CalendarAdditionalInfo& out_additional_info, s64 time, 49 CalendarAdditionalInfo& out_additional_info, s64 time,
49 Tz::Rule& rule); 50 const Tz::Rule& rule);
50 Result ToPosixTimeImpl(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 51 Result ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, size_t out_times_max_count,
51 CalendarTime& calendar, Tz::Rule& rule, s32 is_dst); 52 const CalendarTime& calendar, const Tz::Rule& rule, s32 is_dst);
52 53
53 bool m_initialized{}; 54 bool m_initialized{};
54 std::recursive_mutex m_mutex; 55 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 e304c8387..eb81f5b03 100644
--- a/src/core/hle/service/psc/time/time_zone_service.cpp
+++ b/src/core/hle/service/psc/time/time_zone_service.cpp
@@ -2,7 +2,10 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <tz/tz.h> 4#include <tz/tz.h>
5
6#include "common/scope_exit.h"
5#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/service/cmif_serialization.h"
6#include "core/hle/service/psc/time/time_zone_service.h" 9#include "core/hle/service/psc/time/time_zone_service.h"
7 10
8namespace Service::PSC::Time { 11namespace Service::PSC::Time {
@@ -14,276 +17,149 @@ TimeZoneService::TimeZoneService(Core::System& system_, StandardSteadyClockCore&
14 can_write_timezone_device_location} { 17 can_write_timezone_device_location} {
15 // clang-format off 18 // clang-format off
16 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
17 {0, &TimeZoneService::Handle_GetDeviceLocationName, "GetDeviceLocationName"}, 20 {0, D<&TimeZoneService::GetDeviceLocationName>, "GetDeviceLocationName"},
18 {1, &TimeZoneService::Handle_SetDeviceLocationName, "SetDeviceLocationName"}, 21 {1, D<&TimeZoneService::SetDeviceLocationName>, "SetDeviceLocationName"},
19 {2, &TimeZoneService::Handle_GetTotalLocationNameCount, "GetTotalLocationNameCount"}, 22 {2, D<&TimeZoneService::GetTotalLocationNameCount>, "GetTotalLocationNameCount"},
20 {3, &TimeZoneService::Handle_LoadLocationNameList, "LoadLocationNameList"}, 23 {3, D<&TimeZoneService::LoadLocationNameList>, "LoadLocationNameList"},
21 {4, &TimeZoneService::Handle_LoadTimeZoneRule, "LoadTimeZoneRule"}, 24 {4, D<&TimeZoneService::LoadTimeZoneRule>, "LoadTimeZoneRule"},
22 {5, &TimeZoneService::Handle_GetTimeZoneRuleVersion, "GetTimeZoneRuleVersion"}, 25 {5, D<&TimeZoneService::GetTimeZoneRuleVersion>, "GetTimeZoneRuleVersion"},
23 {6, &TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime, "GetDeviceLocationNameAndUpdatedTime"}, 26 {6, D<&TimeZoneService::GetDeviceLocationNameAndUpdatedTime>, "GetDeviceLocationNameAndUpdatedTime"},
24 {7, &TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule, "SetDeviceLocationNameWithTimeZoneRule"}, 27 {7, D<&TimeZoneService::SetDeviceLocationNameWithTimeZoneRule>, "SetDeviceLocationNameWithTimeZoneRule"},
25 {8, &TimeZoneService::Handle_ParseTimeZoneBinary, "ParseTimeZoneBinary"}, 28 {8, D<&TimeZoneService::ParseTimeZoneBinary>, "ParseTimeZoneBinary"},
26 {20, &TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle, "GetDeviceLocationNameOperationEventReadableHandle"}, 29 {20, D<&TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle>, "GetDeviceLocationNameOperationEventReadableHandle"},
27 {100, &TimeZoneService::Handle_ToCalendarTime, "ToCalendarTime"}, 30 {100, D<&TimeZoneService::ToCalendarTime>, "ToCalendarTime"},
28 {101, &TimeZoneService::Handle_ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, 31 {101, D<&TimeZoneService::ToCalendarTimeWithMyRule>, "ToCalendarTimeWithMyRule"},
29 {201, &TimeZoneService::Handle_ToPosixTime, "ToPosixTime"}, 32 {201, D<&TimeZoneService::ToPosixTime>, "ToPosixTime"},
30 {202, &TimeZoneService::Handle_ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, 33 {202, D<&TimeZoneService::ToPosixTimeWithMyRule>, "ToPosixTimeWithMyRule"},
31 }; 34 };
32 // clang-format on 35 // clang-format on
33 RegisterHandlers(functions); 36 RegisterHandlers(functions);
34} 37}
35 38
36void TimeZoneService::Handle_GetDeviceLocationName(HLERequestContext& ctx) { 39Result TimeZoneService::GetDeviceLocationName(Out<LocationName> out_location_name) {
37 LOG_DEBUG(Service_Time, "called."); 40 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_location_name={}", *out_location_name); });
38
39 LocationName name{};
40 auto res = GetDeviceLocationName(name);
41
42 IPC::ResponseBuilder rb{ctx, 2 + sizeof(LocationName) / sizeof(u32)};
43 rb.Push(res);
44 rb.PushRaw<LocationName>(name);
45}
46
47void TimeZoneService::Handle_SetDeviceLocationName(HLERequestContext& ctx) {
48 LOG_DEBUG(Service_Time, "called.");
49
50 IPC::RequestParser rp{ctx};
51 [[maybe_unused]] auto name{rp.PopRaw<LocationName>()};
52
53 if (!m_can_write_timezone_device_location) {
54 IPC::ResponseBuilder rb{ctx, 2};
55 rb.Push(ResultPermissionDenied);
56 return;
57 }
58
59 IPC::ResponseBuilder rb{ctx, 2};
60 rb.Push(ResultNotImplemented);
61}
62
63void TimeZoneService::Handle_GetTotalLocationNameCount(HLERequestContext& ctx) {
64 LOG_DEBUG(Service_Time, "called.");
65
66 u32 count{};
67 auto res = GetTotalLocationNameCount(count);
68
69 IPC::ResponseBuilder rb{ctx, 3};
70 rb.Push(res);
71 rb.Push(count);
72}
73
74void TimeZoneService::Handle_LoadLocationNameList(HLERequestContext& ctx) {
75 LOG_DEBUG(Service_Time, "called.");
76 41
77 IPC::ResponseBuilder rb{ctx, 2}; 42 R_RETURN(m_time_zone.GetLocationName(*out_location_name));
78 rb.Push(ResultNotImplemented);
79} 43}
80 44
81void TimeZoneService::Handle_LoadTimeZoneRule(HLERequestContext& ctx) { 45Result TimeZoneService::SetDeviceLocationName(LocationName& location_name) {
82 LOG_DEBUG(Service_Time, "called."); 46 LOG_DEBUG(Service_Time, "called. This function is not implemented!");
83 47
84 IPC::ResponseBuilder rb{ctx, 2}; 48 R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied);
85 rb.Push(ResultNotImplemented); 49 R_RETURN(ResultNotImplemented);
86} 50}
87 51
88void TimeZoneService::Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx) { 52Result TimeZoneService::GetTotalLocationNameCount(Out<u32> out_count) {
89 LOG_DEBUG(Service_Time, "called."); 53 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_count={}", *out_count); });
90
91 RuleVersion rule_version{};
92 auto res = GetTimeZoneRuleVersion(rule_version);
93 54
94 IPC::ResponseBuilder rb{ctx, 2 + sizeof(RuleVersion) / sizeof(u32)}; 55 R_RETURN(m_time_zone.GetTotalLocationCount(*out_count));
95 rb.Push(res);
96 rb.PushRaw<RuleVersion>(rule_version);
97} 56}
98 57
99void TimeZoneService::Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx) { 58Result TimeZoneService::LoadLocationNameList(
100 LOG_DEBUG(Service_Time, "called."); 59 Out<u32> out_count, OutArray<LocationName, BufferAttr_HipcMapAlias> out_names, u32 index) {
101 60 LOG_DEBUG(Service_Time, "called. This function is not implemented!");
102 LocationName name{};
103 SteadyClockTimePoint time_point{};
104 auto res = GetDeviceLocationNameAndUpdatedTime(time_point, name);
105 61
106 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(LocationName) / sizeof(u32)) + 62 R_RETURN(ResultNotImplemented);
107 (sizeof(SteadyClockTimePoint) / sizeof(u32))};
108 rb.Push(res);
109 rb.PushRaw<LocationName>(name);
110 rb.PushRaw<SteadyClockTimePoint>(time_point);
111} 63}
112 64
113void TimeZoneService::Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx) { 65Result TimeZoneService::LoadTimeZoneRule(OutRule out_rule, LocationName& location_name) {
114 LOG_DEBUG(Service_Time, "called."); 66 LOG_DEBUG(Service_Time, "called. This function is not implemented!");
115
116 IPC::RequestParser rp{ctx};
117 auto name{rp.PopRaw<LocationName>()};
118
119 auto binary{ctx.ReadBuffer()};
120 auto res = SetDeviceLocationNameWithTimeZoneRule(name, binary);
121 67
122 IPC::ResponseBuilder rb{ctx, 2}; 68 R_RETURN(ResultNotImplemented);
123 rb.Push(res);
124} 69}
125 70
126void TimeZoneService::Handle_ParseTimeZoneBinary(HLERequestContext& ctx) { 71Result TimeZoneService::GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version) {
127 LOG_DEBUG(Service_Time, "called."); 72 SCOPE_EXIT({ LOG_DEBUG(Service_Time, "called. out_rule_version={}", *out_rule_version); });
128
129 auto binary{ctx.ReadBuffer()};
130 73
131 Tz::Rule rule{}; 74 R_RETURN(m_time_zone.GetRuleVersion(*out_rule_version));
132 auto res = ParseTimeZoneBinary(rule, binary);
133
134 ctx.WriteBuffer(rule);
135
136 IPC::ResponseBuilder rb{ctx, 2};
137 rb.Push(res);
138} 75}
139 76
140void TimeZoneService::Handle_GetDeviceLocationNameOperationEventReadableHandle( 77Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(
141 HLERequestContext& ctx) { 78 Out<LocationName> out_location_name, Out<SteadyClockTimePoint> out_time_point) {
142 LOG_DEBUG(Service_Time, "called."); 79 SCOPE_EXIT({
80 LOG_DEBUG(Service_Time, "called. out_location_name={} out_time_point={}",
81 *out_location_name, *out_time_point);
82 });
143 83
144 IPC::ResponseBuilder rb{ctx, 2}; 84 R_TRY(m_time_zone.GetLocationName(*out_location_name));
145 rb.Push(ResultNotImplemented); 85 R_RETURN(m_time_zone.GetTimePoint(*out_time_point));
146} 86}
147 87
148void TimeZoneService::Handle_ToCalendarTime(HLERequestContext& ctx) { 88Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(
149 LOG_DEBUG(Service_Time, "called."); 89 LocationName& location_name, InBuffer<BufferAttr_HipcAutoSelect> binary) {
150 90 LOG_DEBUG(Service_Time, "called. location_name={}", location_name);
151 IPC::RequestParser rp{ctx};
152 auto time{rp.Pop<s64>()};
153 91
154 auto rule_buffer{ctx.ReadBuffer()}; 92 R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied);
155 Tz::Rule rule{}; 93 R_TRY(m_time_zone.ParseBinary(location_name, binary));
156 std::memcpy(&rule, rule_buffer.data(), sizeof(Tz::Rule));
157
158 CalendarTime calendar_time{};
159 CalendarAdditionalInfo additional_info{};
160 auto res = ToCalendarTime(calendar_time, additional_info, time, rule);
161
162 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) +
163 (sizeof(CalendarAdditionalInfo) / sizeof(u32))};
164 rb.Push(res);
165 rb.PushRaw<CalendarTime>(calendar_time);
166 rb.PushRaw<CalendarAdditionalInfo>(additional_info);
167}
168
169void TimeZoneService::Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx) {
170 LOG_DEBUG(Service_Time, "called.");
171
172 IPC::RequestParser rp{ctx};
173 auto time{rp.Pop<s64>()};
174 94
175 CalendarTime calendar_time{}; 95 SteadyClockTimePoint time_point{};
176 CalendarAdditionalInfo additional_info{}; 96 R_TRY(m_clock_core.GetCurrentTimePoint(time_point));
177 auto res = ToCalendarTimeWithMyRule(calendar_time, additional_info, time);
178 97
179 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(CalendarTime) / sizeof(u32)) + 98 m_time_zone.SetTimePoint(time_point);
180 (sizeof(CalendarAdditionalInfo) / sizeof(u32))}; 99 R_SUCCEED();
181 rb.Push(res);
182 rb.PushRaw<CalendarTime>(calendar_time);
183 rb.PushRaw<CalendarAdditionalInfo>(additional_info);
184} 100}
185 101
186void TimeZoneService::Handle_ToPosixTime(HLERequestContext& ctx) { 102Result TimeZoneService::ParseTimeZoneBinary(OutRule out_rule,
103 InBuffer<BufferAttr_HipcAutoSelect> binary) {
187 LOG_DEBUG(Service_Time, "called."); 104 LOG_DEBUG(Service_Time, "called.");
188 105
189 IPC::RequestParser rp{ctx}; 106 R_RETURN(m_time_zone.ParseBinaryInto(*out_rule, binary));
190 auto calendar{rp.PopRaw<CalendarTime>()};
191
192 auto binary{ctx.ReadBuffer()};
193
194 Tz::Rule rule{};
195 std::memcpy(&rule, binary.data(), sizeof(Tz::Rule));
196
197 u32 count{};
198 std::array<s64, 2> times{};
199 u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
200
201 auto res = ToPosixTime(count, times, times_count, calendar, rule);
202
203 ctx.WriteBuffer(times);
204
205 IPC::ResponseBuilder rb{ctx, 3};
206 rb.Push(res);
207 rb.Push(count);
208} 107}
209 108
210void TimeZoneService::Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx) { 109Result TimeZoneService::GetDeviceLocationNameOperationEventReadableHandle(
211 LOG_DEBUG(Service_Time, "called."); 110 OutCopyHandle<Kernel::KReadableEvent> out_event) {
212 111 LOG_DEBUG(Service_Time, "called. This function is not implemented!");
213 IPC::RequestParser rp{ctx};
214 auto calendar{rp.PopRaw<CalendarTime>()};
215 112
216 u32 count{}; 113 R_RETURN(ResultNotImplemented);
217 std::array<s64, 2> times{};
218 u32 times_count{static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(s64))};
219
220 auto res = ToPosixTimeWithMyRule(count, times, times_count, calendar);
221
222 ctx.WriteBuffer(times);
223
224 IPC::ResponseBuilder rb{ctx, 3};
225 rb.Push(res);
226 rb.Push(count);
227} 114}
228 115
229// =============================== Implementations =========================== 116Result TimeZoneService::ToCalendarTime(Out<CalendarTime> out_calendar_time,
230 117 Out<CalendarAdditionalInfo> out_additional_info, s64 time,
231Result TimeZoneService::GetDeviceLocationName(LocationName& out_location_name) { 118 InRule rule) {
232 R_RETURN(m_time_zone.GetLocationName(out_location_name)); 119 SCOPE_EXIT({
233} 120 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
121 *out_calendar_time, *out_additional_info);
122 });
234 123
235Result TimeZoneService::GetTotalLocationNameCount(u32& out_count) { 124 R_RETURN(
236 R_RETURN(m_time_zone.GetTotalLocationCount(out_count)); 125 m_time_zone.ToCalendarTime(*out_calendar_time, *out_additional_info, time, *rule.Get()));
237}
238
239Result TimeZoneService::GetTimeZoneRuleVersion(RuleVersion& out_rule_version) {
240 R_RETURN(m_time_zone.GetRuleVersion(out_rule_version));
241}
242
243Result TimeZoneService::GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point,
244 LocationName& location_name) {
245 R_TRY(m_time_zone.GetLocationName(location_name));
246 R_RETURN(m_time_zone.GetTimePoint(out_time_point));
247} 126}
248 127
249Result TimeZoneService::SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name, 128Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time,
250 std::span<const u8> binary) { 129 Out<CalendarAdditionalInfo> out_additional_info,
251 R_UNLESS(m_can_write_timezone_device_location, ResultPermissionDenied); 130 s64 time) {
252 R_TRY(m_time_zone.ParseBinary(location_name, binary)); 131 SCOPE_EXIT({
253 132 LOG_DEBUG(Service_Time, "called. time={} out_calendar_time={} out_additional_info={}", time,
254 SteadyClockTimePoint time_point{}; 133 *out_calendar_time, *out_additional_info);
255 R_TRY(m_clock_core.GetCurrentTimePoint(time_point)); 134 });
256 135
257 m_time_zone.SetTimePoint(time_point); 136 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(*out_calendar_time, *out_additional_info, time));
258 R_SUCCEED();
259} 137}
260 138
261Result TimeZoneService::ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary) { 139Result TimeZoneService::ToPosixTime(Out<u32> out_count,
262 R_RETURN(m_time_zone.ParseBinaryInto(out_rule, binary)); 140 OutArray<s64, BufferAttr_HipcPointer> out_times,
263} 141 const CalendarTime& calendar_time, InRule rule) {
142 SCOPE_EXIT({
143 LOG_DEBUG(Service_Time,
144 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
145 calendar_time, *out_count, out_times[0], out_times[1]);
146 });
264 147
265Result TimeZoneService::ToCalendarTime(CalendarTime& out_calendar_time, 148 R_RETURN(
266 CalendarAdditionalInfo& out_additional_info, s64 time, 149 m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule));
267 Tz::Rule& rule) {
268 R_RETURN(m_time_zone.ToCalendarTime(out_calendar_time, out_additional_info, time, rule));
269}
270
271Result TimeZoneService::ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time,
272 CalendarAdditionalInfo& out_additional_info,
273 s64 time) {
274 R_RETURN(m_time_zone.ToCalendarTimeWithMyRule(out_calendar_time, out_additional_info, time));
275} 150}
276 151
277Result TimeZoneService::ToPosixTime(u32& out_count, std::span<s64, 2> out_times, 152Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count,
278 u32 out_times_count, CalendarTime& calendar_time, 153 OutArray<s64, BufferAttr_HipcPointer> out_times,
279 Tz::Rule& rule) { 154 const CalendarTime& calendar_time) {
280 R_RETURN(m_time_zone.ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule)); 155 SCOPE_EXIT({
281} 156 LOG_DEBUG(Service_Time,
157 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
158 calendar_time, *out_count, out_times[0], out_times[1]);
159 });
282 160
283Result TimeZoneService::ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times,
284 u32 out_times_count, CalendarTime& calendar_time) {
285 R_RETURN( 161 R_RETURN(
286 m_time_zone.ToPosixTimeWithMyRule(out_count, out_times, out_times_count, calendar_time)); 162 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time));
287} 163}
288 164
289} // namespace Service::PSC::Time 165} // 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 074c1d4ae..6eb9ddc4b 100644
--- a/src/core/hle/service/psc/time/time_zone_service.h
+++ b/src/core/hle/service/psc/time/time_zone_service.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/ipc_helpers.h" 7#include "core/hle/service/ipc_helpers.h"
7#include "core/hle/service/psc/time/common.h" 8#include "core/hle/service/psc/time/common.h"
8#include "core/hle/service/psc/time/manager.h" 9#include "core/hle/service/psc/time/manager.h"
@@ -20,45 +21,41 @@ struct Rule;
20namespace Service::PSC::Time { 21namespace Service::PSC::Time {
21 22
22class TimeZoneService final : public ServiceFramework<TimeZoneService> { 23class TimeZoneService final : public ServiceFramework<TimeZoneService> {
24 using InRule = InLargeData<Tz::Rule, BufferAttr_HipcMapAlias>;
25 using OutRule = OutLargeData<Tz::Rule, BufferAttr_HipcMapAlias>;
26
23public: 27public:
24 explicit TimeZoneService(Core::System& system, StandardSteadyClockCore& clock_core, 28 explicit TimeZoneService(Core::System& system, StandardSteadyClockCore& clock_core,
25 TimeZone& time_zone, bool can_write_timezone_device_location); 29 TimeZone& time_zone, bool can_write_timezone_device_location);
26 30
27 ~TimeZoneService() override = default; 31 ~TimeZoneService() override = default;
28 32
29 Result GetDeviceLocationName(LocationName& out_location_name); 33 Result GetDeviceLocationName(Out<LocationName> out_location_name);
30 Result GetTotalLocationNameCount(u32& out_count); 34 Result SetDeviceLocationName(LocationName& location_name);
31 Result GetTimeZoneRuleVersion(RuleVersion& out_rule_version); 35 Result GetTotalLocationNameCount(Out<u32> out_count);
32 Result GetDeviceLocationNameAndUpdatedTime(SteadyClockTimePoint& out_time_point, 36 Result LoadLocationNameList(Out<u32> out_count,
33 LocationName& location_name); 37 OutArray<LocationName, BufferAttr_HipcMapAlias> out_names,
38 u32 index);
39 Result LoadTimeZoneRule(OutRule out_rule, LocationName& location_name);
40 Result GetTimeZoneRuleVersion(Out<RuleVersion> out_rule_version);
41 Result GetDeviceLocationNameAndUpdatedTime(Out<LocationName> location_name,
42 Out<SteadyClockTimePoint> out_time_point);
34 Result SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name, 43 Result SetDeviceLocationNameWithTimeZoneRule(LocationName& location_name,
35 std::span<const u8> binary); 44 InBuffer<BufferAttr_HipcAutoSelect> binary);
36 Result ParseTimeZoneBinary(Tz::Rule& out_rule, std::span<const u8> binary); 45 Result ParseTimeZoneBinary(OutRule out_rule, InBuffer<BufferAttr_HipcAutoSelect> binary);
37 Result ToCalendarTime(CalendarTime& out_calendar_time, 46 Result GetDeviceLocationNameOperationEventReadableHandle(
38 CalendarAdditionalInfo& out_additional_info, s64 time, Tz::Rule& rule); 47 OutCopyHandle<Kernel::KReadableEvent> out_event);
39 Result ToCalendarTimeWithMyRule(CalendarTime& out_calendar_time, 48 Result ToCalendarTime(Out<CalendarTime> out_calendar_time,
40 CalendarAdditionalInfo& out_additional_info, s64 time); 49 Out<CalendarAdditionalInfo> out_additional_info, s64 time, InRule rule);
41 Result ToPosixTime(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 50 Result ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time,
42 CalendarTime& calendar_time, Tz::Rule& rule); 51 Out<CalendarAdditionalInfo> out_additional_info, s64 time);
43 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64, 2> out_times, u32 out_times_count, 52 Result ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
44 CalendarTime& calendar_time); 53 const CalendarTime& calendar_time, InRule rule);
54 Result ToPosixTimeWithMyRule(Out<u32> out_count,
55 OutArray<s64, BufferAttr_HipcPointer> out_times,
56 const CalendarTime& calendar_time);
45 57
46private: 58private:
47 void Handle_GetDeviceLocationName(HLERequestContext& ctx);
48 void Handle_SetDeviceLocationName(HLERequestContext& ctx);
49 void Handle_GetTotalLocationNameCount(HLERequestContext& ctx);
50 void Handle_LoadLocationNameList(HLERequestContext& ctx);
51 void Handle_LoadTimeZoneRule(HLERequestContext& ctx);
52 void Handle_GetTimeZoneRuleVersion(HLERequestContext& ctx);
53 void Handle_GetDeviceLocationNameAndUpdatedTime(HLERequestContext& ctx);
54 void Handle_SetDeviceLocationNameWithTimeZoneRule(HLERequestContext& ctx);
55 void Handle_ParseTimeZoneBinary(HLERequestContext& ctx);
56 void Handle_GetDeviceLocationNameOperationEventReadableHandle(HLERequestContext& ctx);
57 void Handle_ToCalendarTime(HLERequestContext& ctx);
58 void Handle_ToCalendarTimeWithMyRule(HLERequestContext& ctx);
59 void Handle_ToPosixTime(HLERequestContext& ctx);
60 void Handle_ToPosixTimeWithMyRule(HLERequestContext& ctx);
61
62 Core::System& m_system; 59 Core::System& m_system;
63 60
64 StandardSteadyClockCore& m_clock_core; 61 StandardSteadyClockCore& m_clock_core;
diff --git a/src/core/hle/service/set/setting_formats/system_settings.cpp b/src/core/hle/service/set/setting_formats/system_settings.cpp
index 16ded43bf..7231ff78e 100644
--- a/src/core/hle/service/set/setting_formats/system_settings.cpp
+++ b/src/core/hle/service/set/setting_formats/system_settings.cpp
@@ -45,7 +45,7 @@ SystemSettings DefaultSystemSettings() {
45 .console_sleep_plan = ConsoleSleepPlan::Sleep1Hour, 45 .console_sleep_plan = ConsoleSleepPlan::Sleep1Hour,
46 }; 46 };
47 47
48 settings.device_time_zone_location_name = {"UTC"}; 48 settings.device_time_zone_location_name = Service::PSC::Time::LocationName{"UTC"};
49 settings.user_system_clock_automatic_correction_enabled = true; 49 settings.user_system_clock_automatic_correction_enabled = true;
50 50
51 settings.primary_album_storage = PrimaryAlbumStorage::SdCard; 51 settings.primary_album_storage = PrimaryAlbumStorage::SdCard;
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index c889aec47..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 @@
25namespace Service::Set { 25namespace Service::Set {
26 26
27namespace { 27namespace {
28constexpr u32 SETTINGS_VERSION{2u}; 28constexpr u32 SETTINGS_VERSION{3u};
29constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't'); 29constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't');
30struct SettingsHeader { 30struct SettingsHeader {
31 u64 magic; 31 u64 magic;
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 {
24 CONNRESET = 104, 24 CONNRESET = 104,
25 NOTCONN = 107, 25 NOTCONN = 107,
26 TIMEDOUT = 110, 26 TIMEDOUT = 110,
27 CONNREFUSED = 111,
27 INPROGRESS = 115, 28 INPROGRESS = 115,
28}; 29};
29 30
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) {
25 return Errno::MFILE; 25 return Errno::MFILE;
26 case Network::Errno::PIPE: 26 case Network::Errno::PIPE:
27 return Errno::PIPE; 27 return Errno::PIPE;
28 case Network::Errno::CONNREFUSED:
29 return Errno::CONNREFUSED;
28 case Network::Errno::NOTCONN: 30 case Network::Errno::NOTCONN:
29 return Errno::NOTCONN; 31 return Errno::NOTCONN;
30 case Network::Errno::TIMEDOUT: 32 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..dab1905cc 100644
--- a/src/core/hle/service/vi/display/vi_display.cpp
+++ b/src/core/hle/service/vi/display/vi_display.cpp
@@ -53,7 +53,7 @@ Display::~Display() {
53Layer& Display::GetLayer(std::size_t index) { 53Layer& Display::GetLayer(std::size_t index) {
54 size_t i = 0; 54 size_t i = 0;
55 for (auto& layer : layers) { 55 for (auto& layer : layers) {
56 if (!layer->IsOpen()) { 56 if (!layer->IsOpen() || !layer->IsVisible()) {
57 continue; 57 continue;
58 } 58 }
59 59
@@ -68,7 +68,7 @@ Layer& Display::GetLayer(std::size_t index) {
68} 68}
69 69
70size_t Display::GetNumLayers() const { 70size_t Display::GetNumLayers() const {
71 return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); 71 return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen() && l->IsVisible(); });
72} 72}
73 73
74Kernel::KReadableEvent* Display::GetVSyncEvent() { 74Kernel::KReadableEvent* Display::GetVSyncEvent() {
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_,
9 android::BufferQueueProducer& binder_, 9 android::BufferQueueProducer& binder_,
10 std::shared_ptr<android::BufferItemConsumer>&& consumer_) 10 std::shared_ptr<android::BufferItemConsumer>&& consumer_)
11 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, 11 : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_},
12 consumer{std::move(consumer_)}, open{false} {} 12 consumer{std::move(consumer_)}, open{false}, visible{true} {}
13 13
14Layer::~Layer() = default; 14Layer::~Layer() = default;
15 15
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:
72 return core; 72 return core;
73 } 73 }
74 74
75 bool IsVisible() const {
76 return visible;
77 }
78
79 void SetVisibility(bool v) {
80 visible = v;
81 }
82
75 bool IsOpen() const { 83 bool IsOpen() const {
76 return open; 84 return open;
77 } 85 }
@@ -91,6 +99,7 @@ private:
91 android::BufferQueueProducer& binder; 99 android::BufferQueueProducer& binder;
92 std::shared_ptr<android::BufferItemConsumer> consumer; 100 std::shared_ptr<android::BufferItemConsumer> consumer;
93 bool open; 101 bool open;
102 bool visible;
94}; 103};
95 104
96} // namespace Service::VI 105} // namespace Service::VI
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 1f3d82c57..73058db9a 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -535,6 +535,12 @@ public:
535 RegisterHandlers(functions); 535 RegisterHandlers(functions);
536 } 536 }
537 537
538 ~IApplicationDisplayService() {
539 for (const auto layer_id : stray_layer_ids) {
540 nvnflinger.DestroyLayer(layer_id);
541 }
542 }
543
538private: 544private:
539 enum class ConvertedScaleMode : u64 { 545 enum class ConvertedScaleMode : u64 {
540 Freeze = 0, 546 Freeze = 0,
@@ -770,6 +776,7 @@ private:
770 return; 776 return;
771 } 777 }
772 778
779 stray_layer_ids.push_back(*layer_id);
773 const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id); 780 const auto buffer_queue_id = nvnflinger.FindBufferQueueId(display_id, *layer_id);
774 if (!buffer_queue_id) { 781 if (!buffer_queue_id) {
775 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id); 782 LOG_ERROR(Service_VI, "Buffer queue id not found! display_id={}", display_id);
@@ -916,6 +923,7 @@ private:
916 923
917 Nvnflinger::Nvnflinger& nvnflinger; 924 Nvnflinger::Nvnflinger& nvnflinger;
918 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server; 925 Nvnflinger::HosBinderDriverServer& hos_binder_driver_server;
926 std::vector<u64> stray_layer_ids;
919 bool vsync_event_fetched{false}; 927 bool vsync_event_fetched{false};
920}; 928};
921 929
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() {
693 sockaddr_in addr; 693 sockaddr_in addr;
694 socklen_t addrlen = sizeof(addr); 694 socklen_t addrlen = sizeof(addr);
695 695
696 std::vector<WSAPOLLFD> host_pollfds{ 696 const bool wait_for_accept = !is_non_blocking;
697 WSAPOLLFD{fd, POLLIN, 0}, 697 if (wait_for_accept) {
698 WSAPOLLFD{GetInterruptSocket(), POLLIN, 0}, 698 std::vector<WSAPOLLFD> host_pollfds{
699 }; 699 WSAPOLLFD{fd, POLLIN, 0},
700 700 WSAPOLLFD{GetInterruptSocket(), POLLIN, 0},
701 while (true) { 701 };
702 const int pollres = 702
703 WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), -1); 703 while (true) {
704 if (host_pollfds[1].revents != 0) { 704 const int pollres =
705 // Interrupt signaled before a client could be accepted, break 705 WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), -1);
706 return {AcceptResult{}, Errno::AGAIN}; 706 if (host_pollfds[1].revents != 0) {
707 } 707 // Interrupt signaled before a client could be accepted, break
708 if (pollres > 0) { 708 return {AcceptResult{}, Errno::AGAIN};
709 break; 709 }
710 if (pollres > 0) {
711 break;
712 }
710 } 713 }
711 } 714 }
712 715
@@ -913,6 +916,7 @@ Errno Socket::SetRcvTimeo(u32 value) {
913 916
914Errno Socket::SetNonBlock(bool enable) { 917Errno Socket::SetNonBlock(bool enable) {
915 if (EnableNonBlock(fd, enable)) { 918 if (EnableNonBlock(fd, enable)) {
919 is_non_blocking = enable;
916 return Errno::SUCCESS; 920 return Errno::SUCCESS;
917 } 921 }
918 return GetAndLogLastError(); 922 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:
166 bool IsOpened() const override; 166 bool IsOpened() const override;
167 167
168 void HandleProxyPacket(const ProxyPacket& packet) override; 168 void HandleProxyPacket(const ProxyPacket& packet) override;
169
170private:
171 bool is_non_blocking = false;
169}; 172};
170 173
171std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout); 174std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);
diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt
index 136109a0c..c0dcc0241 100644
--- a/src/dedicated_room/CMakeLists.txt
+++ b/src/dedicated_room/CMakeLists.txt
@@ -7,8 +7,6 @@ add_executable(yuzu-room
7 yuzu_room.rc 7 yuzu_room.rc
8) 8)
9 9
10create_target_directory_groups(yuzu-room)
11
12target_link_libraries(yuzu-room PRIVATE common network) 10target_link_libraries(yuzu-room PRIVATE common network)
13if (ENABLE_WEB_SERVICE) 11if (ENABLE_WEB_SERVICE)
14 target_compile_definitions(yuzu-room PRIVATE -DENABLE_WEB_SERVICE) 12 target_compile_definitions(yuzu-room PRIVATE -DENABLE_WEB_SERVICE)
@@ -28,3 +26,5 @@ endif()
28if (YUZU_USE_PRECOMPILED_HEADERS) 26if (YUZU_USE_PRECOMPILED_HEADERS)
29 target_precompile_headers(yuzu-room PRIVATE precompiled_headers.h) 27 target_precompile_headers(yuzu-room PRIVATE precompiled_headers.h)
30endif() 28endif()
29
30create_target_directory_groups(yuzu-room)
diff --git a/src/hid_core/CMakeLists.txt b/src/hid_core/CMakeLists.txt
index 055954224..2699e1599 100644
--- a/src/hid_core/CMakeLists.txt
+++ b/src/hid_core/CMakeLists.txt
@@ -96,6 +96,7 @@ add_library(hid_core STATIC
96 resources/system_buttons/home_button.h 96 resources/system_buttons/home_button.h
97 resources/system_buttons/sleep_button.cpp 97 resources/system_buttons/sleep_button.cpp
98 resources/system_buttons/sleep_button.h 98 resources/system_buttons/sleep_button.h
99 resources/system_buttons/system_button_types.h
99 resources/touch_screen/gesture.cpp 100 resources/touch_screen/gesture.cpp
100 resources/touch_screen/gesture.h 101 resources/touch_screen/gesture.h
101 resources/touch_screen/gesture_handler.cpp 102 resources/touch_screen/gesture_handler.cpp
diff --git a/src/hid_core/hid_types.h b/src/hid_core/hid_types.h
index 3cf12f6e5..1b2fc6295 100644
--- a/src/hid_core/hid_types.h
+++ b/src/hid_core/hid_types.h
@@ -404,7 +404,10 @@ struct NpadPowerInfo {
404static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); 404static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size");
405 405
406struct LedPattern { 406struct LedPattern {
407 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { 407 LedPattern() {
408 raw = 0;
409 }
410 LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
408 position1.Assign(light1); 411 position1.Assign(light1);
409 position2.Assign(light2); 412 position2.Assign(light2);
410 position3.Assign(light3); 413 position3.Assign(light3);
@@ -419,6 +422,16 @@ struct LedPattern {
419 }; 422 };
420}; 423};
421 424
425struct SleepButtonState {
426 union {
427 u64 raw{};
428
429 // Buttons
430 BitField<0, 1, u64> sleep;
431 };
432};
433static_assert(sizeof(SleepButtonState) == 0x8, "SleepButtonState has incorrect size.");
434
422struct HomeButtonState { 435struct HomeButtonState {
423 union { 436 union {
424 u64 raw{}; 437 u64 raw{};
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp
index 8ab26bc36..1a58eff4a 100644
--- a/src/hid_core/resources/npad/npad.cpp
+++ b/src/hid_core/resources/npad/npad.cpp
@@ -956,17 +956,6 @@ Result NPad::SwapNpadAssignment(u64 aruid, Core::HID::NpadIdType npad_id_1,
956 return ResultSuccess; 956 return ResultSuccess;
957} 957}
958 958
959Result NPad::GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const {
960 if (!IsNpadIdValid(npad_id)) {
961 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
962 return ResultInvalidNpadId;
963 }
964 const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
965 const auto& controller = GetControllerFromNpadIdType(aruid, npad_id).device;
966 pattern = controller->GetLedPattern();
967 return ResultSuccess;
968}
969
970Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid, 959Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid,
971 Core::HID::NpadIdType npad_id) const { 960 Core::HID::NpadIdType npad_id) const {
972 std::scoped_lock lock{mutex}; 961 std::scoped_lock lock{mutex};
diff --git a/src/hid_core/resources/npad/npad.h b/src/hid_core/resources/npad/npad.h
index e81cc3abe..4e26ed2e8 100644
--- a/src/hid_core/resources/npad/npad.h
+++ b/src/hid_core/resources/npad/npad.h
@@ -97,8 +97,6 @@ public:
97 Result ResetIsSixAxisSensorDeviceNewlyAssigned( 97 Result ResetIsSixAxisSensorDeviceNewlyAssigned(
98 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle); 98 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle);
99 99
100 Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
101
102 Result IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid, 100 Result IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid,
103 Core::HID::NpadIdType npad_id) const; 101 Core::HID::NpadIdType npad_id) const;
104 Result EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id, 102 Result EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id,
diff --git a/src/hid_core/resources/shared_memory_format.h b/src/hid_core/resources/shared_memory_format.h
index 2ae0004ba..49755c8dc 100644
--- a/src/hid_core/resources/shared_memory_format.h
+++ b/src/hid_core/resources/shared_memory_format.h
@@ -12,6 +12,7 @@
12#include "hid_core/resources/mouse/mouse_types.h" 12#include "hid_core/resources/mouse/mouse_types.h"
13#include "hid_core/resources/npad/npad_types.h" 13#include "hid_core/resources/npad/npad_types.h"
14#include "hid_core/resources/ring_lifo.h" 14#include "hid_core/resources/ring_lifo.h"
15#include "hid_core/resources/system_buttons/system_button_types.h"
15#include "hid_core/resources/touch_screen/touch_types.h" 16#include "hid_core/resources/touch_screen/touch_types.h"
16 17
17namespace Service::HID { 18namespace Service::HID {
@@ -75,24 +76,24 @@ static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000,
75 76
76// This is nn::hid::detail::HomeButtonSharedMemoryFormat 77// This is nn::hid::detail::HomeButtonSharedMemoryFormat
77struct HomeButtonSharedMemoryFormat { 78struct HomeButtonSharedMemoryFormat {
78 CommonHeader header; 79 Lifo<HomeButtonState, HidEntryCount> home_lifo{};
79 INSERT_PADDING_BYTES(0x1E0); 80 INSERT_PADDING_BYTES(0x48);
80}; 81};
81static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200, 82static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200,
82 "HomeButtonSharedMemoryFormat is an invalid size"); 83 "HomeButtonSharedMemoryFormat is an invalid size");
83 84
84// This is nn::hid::detail::SleepButtonSharedMemoryFormat 85// This is nn::hid::detail::SleepButtonSharedMemoryFormat
85struct SleepButtonSharedMemoryFormat { 86struct SleepButtonSharedMemoryFormat {
86 CommonHeader header; 87 Lifo<SleepButtonState, HidEntryCount> sleep_lifo{};
87 INSERT_PADDING_BYTES(0x1E0); 88 INSERT_PADDING_BYTES(0x48);
88}; 89};
89static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200, 90static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200,
90 "SleepButtonSharedMemoryFormat is an invalid size"); 91 "SleepButtonSharedMemoryFormat is an invalid size");
91 92
92// This is nn::hid::detail::CaptureButtonSharedMemoryFormat 93// This is nn::hid::detail::CaptureButtonSharedMemoryFormat
93struct CaptureButtonSharedMemoryFormat { 94struct CaptureButtonSharedMemoryFormat {
94 CommonHeader header; 95 Lifo<CaptureButtonState, HidEntryCount> capture_lifo{};
95 INSERT_PADDING_BYTES(0x1E0); 96 INSERT_PADDING_BYTES(0x48);
96}; 97};
97static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200, 98static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200,
98 "CaptureButtonSharedMemoryFormat is an invalid size"); 99 "CaptureButtonSharedMemoryFormat is an invalid size");
diff --git a/src/hid_core/resources/system_buttons/capture_button.cpp b/src/hid_core/resources/system_buttons/capture_button.cpp
index 70973ae25..95eb60424 100644
--- a/src/hid_core/resources/system_buttons/capture_button.cpp
+++ b/src/hid_core/resources/system_buttons/capture_button.cpp
@@ -2,6 +2,8 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/core_timing.h" 4#include "core/core_timing.h"
5#include "hid_core/frontend/emulated_controller.h"
6#include "hid_core/hid_core.h"
5#include "hid_core/resources/applet_resource.h" 7#include "hid_core/resources/applet_resource.h"
6#include "hid_core/resources/shared_memory_format.h" 8#include "hid_core/resources/shared_memory_format.h"
7#include "hid_core/resources/system_buttons/capture_button.h" 9#include "hid_core/resources/system_buttons/capture_button.h"
@@ -17,10 +19,6 @@ void CaptureButton::OnInit() {}
17void CaptureButton::OnRelease() {} 19void CaptureButton::OnRelease() {}
18 20
19void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 21void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 std::scoped_lock shared_lock{*shared_mutex}; 22 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid(); 23 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid); 24 auto* data = applet_resource->GetAruidData(aruid);
@@ -29,11 +27,21 @@ void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
29 return; 27 return;
30 } 28 }
31 29
32 auto& header = data->shared_memory_format->capture_button.header; 30 auto& shared_memory = data->shared_memory_format->capture_button;
33 header.timestamp = core_timing.GetGlobalTimeNs().count(); 31
34 header.total_entry_count = 17; 32 if (!IsControllerActivated()) {
35 header.entry_count = 0; 33 shared_memory.capture_lifo.buffer_count = 0;
36 header.last_entry_index = 0; 34 shared_memory.capture_lifo.buffer_tail = 0;
35 return;
36 }
37
38 const auto& last_entry = shared_memory.capture_lifo.ReadCurrentEntry().state;
39 next_state.sampling_number = last_entry.sampling_number + 1;
40
41 auto* controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
42 next_state.buttons.raw = controller->GetHomeButtons().raw;
43
44 shared_memory.capture_lifo.WriteNextEntry(next_state);
37} 45}
38 46
39} // namespace Service::HID 47} // namespace Service::HID
diff --git a/src/hid_core/resources/system_buttons/capture_button.h b/src/hid_core/resources/system_buttons/capture_button.h
index ad95d7cad..f362ef90b 100644
--- a/src/hid_core/resources/system_buttons/capture_button.h
+++ b/src/hid_core/resources/system_buttons/capture_button.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "hid_core/resources/controller_base.h" 6#include "hid_core/resources/controller_base.h"
7#include "hid_core/resources/system_buttons/system_button_types.h"
7 8
8namespace Service::HID { 9namespace Service::HID {
9 10
@@ -22,6 +23,6 @@ public:
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 23 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23 24
24private: 25private:
25 bool smart_update{}; 26 CaptureButtonState next_state{};
26}; 27};
27} // namespace Service::HID 28} // namespace Service::HID
diff --git a/src/hid_core/resources/system_buttons/home_button.cpp b/src/hid_core/resources/system_buttons/home_button.cpp
index f9c1f44b5..f665338f3 100644
--- a/src/hid_core/resources/system_buttons/home_button.cpp
+++ b/src/hid_core/resources/system_buttons/home_button.cpp
@@ -2,6 +2,8 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/core_timing.h" 4#include "core/core_timing.h"
5#include "hid_core/frontend/emulated_controller.h"
6#include "hid_core/hid_core.h"
5#include "hid_core/resources/applet_resource.h" 7#include "hid_core/resources/applet_resource.h"
6#include "hid_core/resources/shared_memory_format.h" 8#include "hid_core/resources/shared_memory_format.h"
7#include "hid_core/resources/system_buttons/home_button.h" 9#include "hid_core/resources/system_buttons/home_button.h"
@@ -17,10 +19,6 @@ void HomeButton::OnInit() {}
17void HomeButton::OnRelease() {} 19void HomeButton::OnRelease() {}
18 20
19void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 21void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 std::scoped_lock shared_lock{*shared_mutex}; 22 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid(); 23 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid); 24 auto* data = applet_resource->GetAruidData(aruid);
@@ -29,11 +27,21 @@ void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
29 return; 27 return;
30 } 28 }
31 29
32 auto& header = data->shared_memory_format->home_button.header; 30 auto& shared_memory = data->shared_memory_format->home_button;
33 header.timestamp = core_timing.GetGlobalTimeNs().count(); 31
34 header.total_entry_count = 17; 32 if (!IsControllerActivated()) {
35 header.entry_count = 0; 33 shared_memory.home_lifo.buffer_count = 0;
36 header.last_entry_index = 0; 34 shared_memory.home_lifo.buffer_tail = 0;
35 return;
36 }
37
38 const auto& last_entry = shared_memory.home_lifo.ReadCurrentEntry().state;
39 next_state.sampling_number = last_entry.sampling_number + 1;
40
41 auto* controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
42 next_state.buttons.raw = controller->GetHomeButtons().raw;
43
44 shared_memory.home_lifo.WriteNextEntry(next_state);
37} 45}
38 46
39} // namespace Service::HID 47} // namespace Service::HID
diff --git a/src/hid_core/resources/system_buttons/home_button.h b/src/hid_core/resources/system_buttons/home_button.h
index ecf8327f4..a9374828d 100644
--- a/src/hid_core/resources/system_buttons/home_button.h
+++ b/src/hid_core/resources/system_buttons/home_button.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "hid_core/resources/controller_base.h" 6#include "hid_core/resources/controller_base.h"
7#include "hid_core/resources/system_buttons/system_button_types.h"
7 8
8namespace Service::HID { 9namespace Service::HID {
9 10
@@ -22,6 +23,6 @@ public:
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 23 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23 24
24private: 25private:
25 bool smart_update{}; 26 HomeButtonState next_state{};
26}; 27};
27} // namespace Service::HID 28} // namespace Service::HID
diff --git a/src/hid_core/resources/system_buttons/sleep_button.cpp b/src/hid_core/resources/system_buttons/sleep_button.cpp
index 22adf501f..159663246 100644
--- a/src/hid_core/resources/system_buttons/sleep_button.cpp
+++ b/src/hid_core/resources/system_buttons/sleep_button.cpp
@@ -17,10 +17,6 @@ void SleepButton::OnInit() {}
17void SleepButton::OnRelease() {} 17void SleepButton::OnRelease() {}
18 18
19void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 19void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
20 if (!smart_update) {
21 return;
22 }
23
24 std::scoped_lock shared_lock{*shared_mutex}; 20 std::scoped_lock shared_lock{*shared_mutex};
25 const u64 aruid = applet_resource->GetActiveAruid(); 21 const u64 aruid = applet_resource->GetActiveAruid();
26 auto* data = applet_resource->GetAruidData(aruid); 22 auto* data = applet_resource->GetAruidData(aruid);
@@ -29,11 +25,20 @@ void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
29 return; 25 return;
30 } 26 }
31 27
32 auto& header = data->shared_memory_format->capture_button.header; 28 auto& shared_memory = data->shared_memory_format->sleep_button;
33 header.timestamp = core_timing.GetGlobalTimeNs().count(); 29
34 header.total_entry_count = 17; 30 if (!IsControllerActivated()) {
35 header.entry_count = 0; 31 shared_memory.sleep_lifo.buffer_count = 0;
36 header.last_entry_index = 0; 32 shared_memory.sleep_lifo.buffer_tail = 0;
33 return;
34 }
35
36 const auto& last_entry = shared_memory.sleep_lifo.ReadCurrentEntry().state;
37 next_state.sampling_number = last_entry.sampling_number + 1;
38
39 next_state.buttons.raw = 0;
40
41 shared_memory.sleep_lifo.WriteNextEntry(next_state);
37} 42}
38 43
39} // namespace Service::HID 44} // namespace Service::HID
diff --git a/src/hid_core/resources/system_buttons/sleep_button.h b/src/hid_core/resources/system_buttons/sleep_button.h
index f9ed38c33..f8ac5031b 100644
--- a/src/hid_core/resources/system_buttons/sleep_button.h
+++ b/src/hid_core/resources/system_buttons/sleep_button.h
@@ -4,6 +4,7 @@
4#pragma once 4#pragma once
5 5
6#include "hid_core/resources/controller_base.h" 6#include "hid_core/resources/controller_base.h"
7#include "hid_core/resources/system_buttons/system_button_types.h"
7 8
8namespace Service::HID { 9namespace Service::HID {
9 10
@@ -22,6 +23,6 @@ public:
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 23 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23 24
24private: 25private:
25 bool smart_update{}; 26 SleepButtonState next_state{};
26}; 27};
27} // namespace Service::HID 28} // namespace Service::HID
diff --git a/src/hid_core/resources/system_buttons/system_button_types.h b/src/hid_core/resources/system_buttons/system_button_types.h
new file mode 100644
index 000000000..929e1dc4c
--- /dev/null
+++ b/src/hid_core/resources/system_buttons/system_button_types.h
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "hid_core/hid_types.h"
7
8namespace Service::HID {
9
10// This is nn::hid::system::SleepButtonState
11struct SleepButtonState {
12 s64 sampling_number{};
13 Core::HID::SleepButtonState buttons;
14};
15static_assert(sizeof(SleepButtonState) == 0x10, "SleepButtonState is an invalid size");
16
17// This is nn::hid::system::HomeButtonState
18struct HomeButtonState {
19 s64 sampling_number{};
20 Core::HID::HomeButtonState buttons;
21};
22static_assert(sizeof(HomeButtonState) == 0x10, "HomeButtonState is an invalid size");
23
24// This is nn::hid::system::SleepButtonState
25struct CaptureButtonState {
26 s64 sampling_number{};
27 Core::HID::CaptureButtonState buttons;
28};
29static_assert(sizeof(CaptureButtonState) == 0x10, "CaptureButtonState is an invalid size");
30
31} // namespace Service::HID
diff --git a/src/hid_core/resources/unique_pad/unique_pad.cpp b/src/hid_core/resources/unique_pad/unique_pad.cpp
index 892bbe3c9..89fc57269 100644
--- a/src/hid_core/resources/unique_pad/unique_pad.cpp
+++ b/src/hid_core/resources/unique_pad/unique_pad.cpp
@@ -28,7 +28,7 @@ void UniquePad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
28 return; 28 return;
29 } 29 }
30 30
31 auto& header = data->shared_memory_format->capture_button.header; 31 auto& header = data->shared_memory_format->unique_pad.header;
32 header.timestamp = core_timing.GetGlobalTimeNs().count(); 32 header.timestamp = core_timing.GetGlobalTimeNs().count();
33 header.total_entry_count = 17; 33 header.total_entry_count = 17;
34 header.entry_count = 0; 34 header.entry_count = 0;
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 5ed0ad0ed..0755ba772 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -289,8 +289,6 @@ add_library(video_core STATIC
289 vulkan_common/vulkan.h 289 vulkan_common/vulkan.h
290) 290)
291 291
292create_target_directory_groups(video_core)
293
294target_link_libraries(video_core PUBLIC common core) 292target_link_libraries(video_core PUBLIC common core)
295target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder) 293target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder)
296 294
@@ -304,7 +302,7 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
304 302
305add_dependencies(video_core host_shaders) 303add_dependencies(video_core host_shaders)
306target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE}) 304target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
307target_link_libraries(video_core PRIVATE sirit Vulkan::Headers GPUOpen::VulkanMemoryAllocator) 305target_link_libraries(video_core PRIVATE sirit Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator)
308 306
309if (ENABLE_NSIGHT_AFTERMATH) 307if (ENABLE_NSIGHT_AFTERMATH)
310 if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK}) 308 if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
@@ -365,3 +363,5 @@ endif()
365if (ANDROID AND ARCHITECTURE_arm64) 363if (ANDROID AND ARCHITECTURE_arm64)
366 target_link_libraries(video_core PRIVATE adrenotools) 364 target_link_libraries(video_core PRIVATE adrenotools)
367endif() 365endif()
366
367create_target_directory_groups(video_core)
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 86a30dcd1..4f1d3b4e3 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -12,6 +12,7 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "video_core/renderer_vulkan/vk_scheduler.h" 13#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/vk_swapchain.h" 14#include "video_core/renderer_vulkan/vk_swapchain.h"
15#include "video_core/vulkan_common/vk_enum_string_helper.h"
15#include "video_core/vulkan_common/vulkan_device.h" 16#include "video_core/vulkan_common/vulkan_device.h"
16#include "video_core/vulkan_common/vulkan_wrapper.h" 17#include "video_core/vulkan_common/vulkan_wrapper.h"
17#include "vulkan/vulkan_core.h" 18#include "vulkan/vulkan_core.h"
@@ -151,7 +152,7 @@ bool Swapchain::AcquireNextImage() {
151 vk::Check(result); 152 vk::Check(result);
152 break; 153 break;
153 default: 154 default:
154 LOG_ERROR(Render_Vulkan, "vkAcquireNextImageKHR returned {}", vk::ToString(result)); 155 LOG_ERROR(Render_Vulkan, "vkAcquireNextImageKHR returned {}", string_VkResult(result));
155 break; 156 break;
156 } 157 }
157 158
@@ -187,7 +188,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
187 vk::Check(result); 188 vk::Check(result);
188 break; 189 break;
189 default: 190 default:
190 LOG_CRITICAL(Render_Vulkan, "Failed to present with error {}", vk::ToString(result)); 191 LOG_CRITICAL(Render_Vulkan, "Failed to present with error {}", string_VkResult(result));
191 break; 192 break;
192 } 193 }
193 ++frame_index; 194 ++frame_index;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 7398ed2ec..a7400adfa 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1431,7 +1431,8 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA
1431 } 1431 }
1432 } 1432 }
1433 }; 1433 };
1434 ForEachSparseImageInRegion(gpu_addr, size_bytes, region_check_gpu); 1434 ForEachSparseImageInRegion(channel_state->gpu_memory.GetID(), gpu_addr, size_bytes,
1435 region_check_gpu);
1435 1436
1436 bool can_rescale = info.rescaleable; 1437 bool can_rescale = info.rescaleable;
1437 bool any_rescaled = false; 1438 bool any_rescaled = false;
@@ -1842,7 +1843,7 @@ void TextureCache<P>::ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, s
1842 if (!storage_id) { 1843 if (!storage_id) {
1843 return; 1844 return;
1844 } 1845 }
1845 auto& gpu_page_table = gpu_page_table_storage[*storage_id]; 1846 auto& gpu_page_table = gpu_page_table_storage[*storage_id * 2];
1846 ForEachGPUPage(gpu_addr, size, 1847 ForEachGPUPage(gpu_addr, size,
1847 [this, &gpu_page_table, &images, gpu_addr, size, func](u64 page) { 1848 [this, &gpu_page_table, &images, gpu_addr, size, func](u64 page) {
1848 const auto it = gpu_page_table.find(page); 1849 const auto it = gpu_page_table.find(page);
@@ -1882,41 +1883,48 @@ void TextureCache<P>::ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, s
1882 1883
1883template <class P> 1884template <class P>
1884template <typename Func> 1885template <typename Func>
1885void TextureCache<P>::ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func) { 1886void TextureCache<P>::ForEachSparseImageInRegion(size_t as_id, GPUVAddr gpu_addr, size_t size,
1887 Func&& func) {
1886 using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type; 1888 using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type;
1887 static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>; 1889 static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
1888 boost::container::small_vector<ImageId, 8> images; 1890 boost::container::small_vector<ImageId, 8> images;
1889 ForEachGPUPage(gpu_addr, size, [this, &images, gpu_addr, size, func](u64 page) { 1891 auto storage_id = getStorageID(as_id);
1890 const auto it = sparse_page_table.find(page); 1892 if (!storage_id) {
1891 if (it == sparse_page_table.end()) { 1893 return;
1892 if constexpr (BOOL_BREAK) { 1894 }
1893 return false; 1895 auto& sparse_page_table = gpu_page_table_storage[*storage_id * 2 + 1];
1894 } else { 1896 ForEachGPUPage(gpu_addr, size,
1895 return; 1897 [this, &sparse_page_table, &images, gpu_addr, size, func](u64 page) {
1896 } 1898 const auto it = sparse_page_table.find(page);
1897 } 1899 if (it == sparse_page_table.end()) {
1898 for (const ImageId image_id : it->second) { 1900 if constexpr (BOOL_BREAK) {
1899 Image& image = slot_images[image_id]; 1901 return false;
1900 if (True(image.flags & ImageFlagBits::Picked)) { 1902 } else {
1901 continue; 1903 return;
1902 } 1904 }
1903 if (!image.OverlapsGPU(gpu_addr, size)) { 1905 }
1904 continue; 1906 for (const ImageId image_id : it->second) {
1905 } 1907 Image& image = slot_images[image_id];
1906 image.flags |= ImageFlagBits::Picked; 1908 if (True(image.flags & ImageFlagBits::Picked)) {
1907 images.push_back(image_id); 1909 continue;
1908 if constexpr (BOOL_BREAK) { 1910 }
1909 if (func(image_id, image)) { 1911 if (!image.OverlapsGPU(gpu_addr, size)) {
1910 return true; 1912 continue;
1911 } 1913 }
1912 } else { 1914 image.flags |= ImageFlagBits::Picked;
1913 func(image_id, image); 1915 images.push_back(image_id);
1914 } 1916 if constexpr (BOOL_BREAK) {
1915 } 1917 if (func(image_id, image)) {
1916 if constexpr (BOOL_BREAK) { 1918 return true;
1917 return false; 1919 }
1918 } 1920 } else {
1919 }); 1921 func(image_id, image);
1922 }
1923 }
1924 if constexpr (BOOL_BREAK) {
1925 return false;
1926 }
1927 });
1920 for (const ImageId image_id : images) { 1928 for (const ImageId image_id : images) {
1921 slot_images[image_id].flags &= ~ImageFlagBits::Picked; 1929 slot_images[image_id].flags &= ~ImageFlagBits::Picked;
1922 } 1930 }
@@ -1988,8 +1996,9 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
1988 sparse_maps.push_back(map_id); 1996 sparse_maps.push_back(map_id);
1989 }); 1997 });
1990 sparse_views.emplace(image_id, std::move(sparse_maps)); 1998 sparse_views.emplace(image_id, std::move(sparse_maps));
1991 ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, 1999 ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, image_id](u64 page) {
1992 [this, image_id](u64 page) { sparse_page_table[page].push_back(image_id); }); 2000 (*channel_state->sparse_page_table)[page].push_back(image_id);
2001 });
1993} 2002}
1994 2003
1995template <class P> 2004template <class P>
@@ -2042,7 +2051,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
2042 return; 2051 return;
2043 } 2052 }
2044 ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, &clear_page_table](u64 page) { 2053 ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, &clear_page_table](u64 page) {
2045 clear_page_table(page, sparse_page_table); 2054 clear_page_table(page, (*channel_state->sparse_page_table));
2046 }); 2055 });
2047 auto it = sparse_views.find(image_id); 2056 auto it = sparse_views.find(image_id);
2048 ASSERT(it != sparse_views.end()); 2057 ASSERT(it != sparse_views.end());
@@ -2496,13 +2505,15 @@ void TextureCache<P>::CreateChannel(struct Tegra::Control::ChannelState& channel
2496 const auto it = channel_map.find(channel.bind_id); 2505 const auto it = channel_map.find(channel.bind_id);
2497 auto* this_state = &channel_storage[it->second]; 2506 auto* this_state = &channel_storage[it->second];
2498 const auto& this_as_ref = address_spaces[channel.memory_manager->GetID()]; 2507 const auto& this_as_ref = address_spaces[channel.memory_manager->GetID()];
2499 this_state->gpu_page_table = &gpu_page_table_storage[this_as_ref.storage_id]; 2508 this_state->gpu_page_table = &gpu_page_table_storage[this_as_ref.storage_id * 2];
2509 this_state->sparse_page_table = &gpu_page_table_storage[this_as_ref.storage_id * 2 + 1];
2500} 2510}
2501 2511
2502/// Bind a channel for execution. 2512/// Bind a channel for execution.
2503template <class P> 2513template <class P>
2504void TextureCache<P>::OnGPUASRegister([[maybe_unused]] size_t map_id) { 2514void TextureCache<P>::OnGPUASRegister([[maybe_unused]] size_t map_id) {
2505 gpu_page_table_storage.emplace_back(); 2515 gpu_page_table_storage.emplace_back();
2516 gpu_page_table_storage.emplace_back();
2506} 2517}
2507 2518
2508} // namespace VideoCommon 2519} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index 8699d40d4..f9aebb293 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -86,6 +86,7 @@ public:
86 std::unordered_map<TSCEntry, SamplerId> samplers; 86 std::unordered_map<TSCEntry, SamplerId> samplers;
87 87
88 TextureCacheGPUMap* gpu_page_table; 88 TextureCacheGPUMap* gpu_page_table;
89 TextureCacheGPUMap* sparse_page_table;
89}; 90};
90 91
91template <class P> 92template <class P>
@@ -357,7 +358,7 @@ private:
357 void ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, size_t size, Func&& func); 358 void ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, size_t size, Func&& func);
358 359
359 template <typename Func> 360 template <typename Func>
360 void ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func); 361 void ForEachSparseImageInRegion(size_t as_id, GPUVAddr gpu_addr, size_t size, Func&& func);
361 362
362 /// Iterates over all the images in a region calling func 363 /// Iterates over all the images in a region calling func
363 template <typename Func> 364 template <typename Func>
@@ -431,7 +432,6 @@ private:
431 std::unordered_map<RenderTargets, FramebufferId> framebuffers; 432 std::unordered_map<RenderTargets, FramebufferId> framebuffers;
432 433
433 std::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table; 434 std::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table;
434 std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>> sparse_page_table;
435 std::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views; 435 std::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views;
436 436
437 DAddr virtual_invalid_space{}; 437 DAddr virtual_invalid_space{};
diff --git a/src/video_core/vulkan_common/vk_enum_string_helper.h b/src/video_core/vulkan_common/vk_enum_string_helper.h
new file mode 100644
index 000000000..a1515814c
--- /dev/null
+++ b/src/video_core/vulkan_common/vk_enum_string_helper.h
@@ -0,0 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "video_core/vulkan_common/vulkan.h"
7
8#include <vulkan/vk_enum_string_helper.h>
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 3966bd61e..f1aa45551 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -9,6 +9,7 @@
9 9
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "video_core/vulkan_common/vk_enum_string_helper.h"
12#include "video_core/vulkan_common/vma.h" 13#include "video_core/vulkan_common/vma.h"
13#include "video_core/vulkan_common/vulkan_wrapper.h" 14#include "video_core/vulkan_common/vulkan_wrapper.h"
14 15
@@ -298,109 +299,7 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
298} 299}
299 300
300const char* Exception::what() const noexcept { 301const char* Exception::what() const noexcept {
301 return ToString(result); 302 return string_VkResult(result);
302}
303
304const char* ToString(VkResult result) noexcept {
305 switch (result) {
306 case VkResult::VK_SUCCESS:
307 return "VK_SUCCESS";
308 case VkResult::VK_NOT_READY:
309 return "VK_NOT_READY";
310 case VkResult::VK_TIMEOUT:
311 return "VK_TIMEOUT";
312 case VkResult::VK_EVENT_SET:
313 return "VK_EVENT_SET";
314 case VkResult::VK_EVENT_RESET:
315 return "VK_EVENT_RESET";
316 case VkResult::VK_INCOMPLETE:
317 return "VK_INCOMPLETE";
318 case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY:
319 return "VK_ERROR_OUT_OF_HOST_MEMORY";
320 case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY:
321 return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
322 case VkResult::VK_ERROR_INITIALIZATION_FAILED:
323 return "VK_ERROR_INITIALIZATION_FAILED";
324 case VkResult::VK_ERROR_DEVICE_LOST:
325 return "VK_ERROR_DEVICE_LOST";
326 case VkResult::VK_ERROR_MEMORY_MAP_FAILED:
327 return "VK_ERROR_MEMORY_MAP_FAILED";
328 case VkResult::VK_ERROR_LAYER_NOT_PRESENT:
329 return "VK_ERROR_LAYER_NOT_PRESENT";
330 case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT:
331 return "VK_ERROR_EXTENSION_NOT_PRESENT";
332 case VkResult::VK_ERROR_FEATURE_NOT_PRESENT:
333 return "VK_ERROR_FEATURE_NOT_PRESENT";
334 case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER:
335 return "VK_ERROR_INCOMPATIBLE_DRIVER";
336 case VkResult::VK_ERROR_TOO_MANY_OBJECTS:
337 return "VK_ERROR_TOO_MANY_OBJECTS";
338 case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED:
339 return "VK_ERROR_FORMAT_NOT_SUPPORTED";
340 case VkResult::VK_ERROR_FRAGMENTED_POOL:
341 return "VK_ERROR_FRAGMENTED_POOL";
342 case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY:
343 return "VK_ERROR_OUT_OF_POOL_MEMORY";
344 case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE:
345 return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
346 case VkResult::VK_ERROR_SURFACE_LOST_KHR:
347 return "VK_ERROR_SURFACE_LOST_KHR";
348 case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
349 return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
350 case VkResult::VK_SUBOPTIMAL_KHR:
351 return "VK_SUBOPTIMAL_KHR";
352 case VkResult::VK_ERROR_OUT_OF_DATE_KHR:
353 return "VK_ERROR_OUT_OF_DATE_KHR";
354 case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
355 return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
356 case VkResult::VK_ERROR_VALIDATION_FAILED_EXT:
357 return "VK_ERROR_VALIDATION_FAILED_EXT";
358 case VkResult::VK_ERROR_INVALID_SHADER_NV:
359 return "VK_ERROR_INVALID_SHADER_NV";
360 case VkResult::VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR:
361 return "VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR";
362 case VkResult::VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR:
363 return "VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR";
364 case VkResult::VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR:
365 return "VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR";
366 case VkResult::VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR:
367 return "VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR";
368 case VkResult::VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR:
369 return "VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR";
370 case VkResult::VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR:
371 return "VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR";
372 case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
373 return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
374 case VkResult::VK_ERROR_FRAGMENTATION_EXT:
375 return "VK_ERROR_FRAGMENTATION_EXT";
376 case VkResult::VK_ERROR_NOT_PERMITTED_EXT:
377 return "VK_ERROR_NOT_PERMITTED_EXT";
378 case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT:
379 return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT";
380 case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
381 return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
382 case VkResult::VK_ERROR_UNKNOWN:
383 return "VK_ERROR_UNKNOWN";
384 case VkResult::VK_THREAD_IDLE_KHR:
385 return "VK_THREAD_IDLE_KHR";
386 case VkResult::VK_THREAD_DONE_KHR:
387 return "VK_THREAD_DONE_KHR";
388 case VkResult::VK_OPERATION_DEFERRED_KHR:
389 return "VK_OPERATION_DEFERRED_KHR";
390 case VkResult::VK_OPERATION_NOT_DEFERRED_KHR:
391 return "VK_OPERATION_NOT_DEFERRED_KHR";
392 case VkResult::VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR:
393 return "VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR";
394 case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT:
395 return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
396 case VkResult::VK_RESULT_MAX_ENUM:
397 return "VK_RESULT_MAX_ENUM";
398 case VkResult::VK_ERROR_COMPRESSION_EXHAUSTED_EXT:
399 return "VK_ERROR_COMPRESSION_EXHAUSTED_EXT";
400 case VkResult::VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT:
401 return "VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT";
402 }
403 return "Unknown";
404} 303}
405 304
406void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept { 305void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept {
@@ -1067,7 +966,7 @@ u32 AvailableVersion(const InstanceDispatch& dld) noexcept {
1067 u32 version; 966 u32 version;
1068 if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) { 967 if (const VkResult result = vkEnumerateInstanceVersion(&version); result != VK_SUCCESS) {
1069 LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1", 968 LOG_ERROR(Render_Vulkan, "vkEnumerateInstanceVersion returned {}, assuming Vulkan 1.1",
1070 ToString(result)); 969 string_VkResult(result));
1071 return VK_API_VERSION_1_1; 970 return VK_API_VERSION_1_1;
1072 } 971 }
1073 return version; 972 return version;
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h
index a0c70797f..757f3c8af 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.h
+++ b/src/video_core/vulkan_common/vulkan_wrapper.h
@@ -125,9 +125,6 @@ private:
125 VkResult result; 125 VkResult result;
126}; 126};
127 127
128/// Converts a VkResult enum into a rodata string
129const char* ToString(VkResult) noexcept;
130
131/// Throws a Vulkan exception if result is not success. 128/// Throws a Vulkan exception if result is not success.
132inline void Check(VkResult result) { 129inline void Check(VkResult result) {
133 if (result != VK_SUCCESS) { 130 if (result != VK_SUCCESS) {
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index bc667b39f..76f06da12 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -378,8 +378,6 @@ elseif(WIN32)
378 endif() 378 endif()
379endif() 379endif()
380 380
381create_target_directory_groups(yuzu)
382
383target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core) 381target_link_libraries(yuzu PRIVATE common core input_common frontend_common network video_core)
384target_link_libraries(yuzu PRIVATE Boost::headers glad Qt${QT_MAJOR_VERSION}::Widgets) 382target_link_libraries(yuzu PRIVATE Boost::headers glad Qt${QT_MAJOR_VERSION}::Widgets)
385target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 383target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
@@ -475,3 +473,5 @@ endif()
475if (YUZU_USE_PRECOMPILED_HEADERS) 473if (YUZU_USE_PRECOMPILED_HEADERS)
476 target_precompile_headers(yuzu PRIVATE precompiled_headers.h) 474 target_precompile_headers(yuzu PRIVATE precompiled_headers.h)
477endif() 475endif()
476
477create_target_directory_groups(yuzu)
diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp
index 79162a491..66edd6acd 100644
--- a/src/yuzu/applets/qt_profile_select.cpp
+++ b/src/yuzu/applets/qt_profile_select.cpp
@@ -162,7 +162,7 @@ void QtProfileSelectionDialog::SelectUser(const QModelIndex& index) {
162 162
163void QtProfileSelectionDialog::SetWindowTitle( 163void QtProfileSelectionDialog::SetWindowTitle(
164 const Core::Frontend::ProfileSelectParameters& parameters) { 164 const Core::Frontend::ProfileSelectParameters& parameters) {
165 using Service::AM::Applets::UiMode; 165 using Service::AM::Frontend::UiMode;
166 switch (parameters.mode) { 166 switch (parameters.mode) {
167 case UiMode::UserCreator: 167 case UiMode::UserCreator:
168 case UiMode::UserCreatorForStarter: 168 case UiMode::UserCreatorForStarter:
@@ -193,7 +193,7 @@ void QtProfileSelectionDialog::SetWindowTitle(
193 193
194void QtProfileSelectionDialog::SetDialogPurpose( 194void QtProfileSelectionDialog::SetDialogPurpose(
195 const Core::Frontend::ProfileSelectParameters& parameters) { 195 const Core::Frontend::ProfileSelectParameters& parameters) {
196 using Service::AM::Applets::UserSelectionPurpose; 196 using Service::AM::Frontend::UserSelectionPurpose;
197 197
198 switch (parameters.purpose) { 198 switch (parameters.purpose) {
199 case UserSelectionPurpose::GameCardRegistration: 199 case UserSelectionPurpose::GameCardRegistration:
diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp
index ac81ace9e..2749e6ed3 100644
--- a/src/yuzu/applets/qt_software_keyboard.cpp
+++ b/src/yuzu/applets/qt_software_keyboard.cpp
@@ -20,7 +20,7 @@
20 20
21namespace { 21namespace {
22 22
23using namespace Service::AM::Applets; 23using namespace Service::AM::Frontend;
24 24
25constexpr float BASE_HEADER_FONT_SIZE = 23.0f; 25constexpr float BASE_HEADER_FONT_SIZE = 23.0f;
26constexpr float BASE_SUB_FONT_SIZE = 17.0f; 26constexpr float BASE_SUB_FONT_SIZE = 17.0f;
@@ -389,7 +389,7 @@ void QtSoftwareKeyboardDialog::ShowNormalKeyboard(QPoint pos, QSize size) {
389} 389}
390 390
391void QtSoftwareKeyboardDialog::ShowTextCheckDialog( 391void QtSoftwareKeyboardDialog::ShowTextCheckDialog(
392 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 392 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
393 std::u16string text_check_message) { 393 std::u16string text_check_message) {
394 switch (text_check_result) { 394 switch (text_check_result) {
395 case SwkbdTextCheckResult::Success: 395 case SwkbdTextCheckResult::Success:
@@ -1612,7 +1612,7 @@ void QtSoftwareKeyboard::ShowNormalKeyboard() const {
1612} 1612}
1613 1613
1614void QtSoftwareKeyboard::ShowTextCheckDialog( 1614void QtSoftwareKeyboard::ShowTextCheckDialog(
1615 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 1615 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
1616 std::u16string text_check_message) const { 1616 std::u16string text_check_message) const {
1617 emit MainWindowShowTextCheckDialog(text_check_result, std::move(text_check_message)); 1617 emit MainWindowShowTextCheckDialog(text_check_result, std::move(text_check_message));
1618} 1618}
@@ -1662,12 +1662,12 @@ void QtSoftwareKeyboard::ExitKeyboard() const {
1662 emit MainWindowExitKeyboard(); 1662 emit MainWindowExitKeyboard();
1663} 1663}
1664 1664
1665void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Applets::SwkbdResult result, 1665void QtSoftwareKeyboard::SubmitNormalText(Service::AM::Frontend::SwkbdResult result,
1666 std::u16string submitted_text, bool confirmed) const { 1666 std::u16string submitted_text, bool confirmed) const {
1667 submit_normal_callback(result, submitted_text, confirmed); 1667 submit_normal_callback(result, submitted_text, confirmed);
1668} 1668}
1669 1669
1670void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, 1670void QtSoftwareKeyboard::SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type,
1671 std::u16string submitted_text, 1671 std::u16string submitted_text,
1672 s32 cursor_position) const { 1672 s32 cursor_position) const {
1673 submit_inline_callback(reply_type, submitted_text, cursor_position); 1673 submit_inline_callback(reply_type, submitted_text, cursor_position);
diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h
index ac23ce047..7e2fdf09e 100644
--- a/src/yuzu/applets/qt_software_keyboard.h
+++ b/src/yuzu/applets/qt_software_keyboard.h
@@ -39,7 +39,7 @@ public:
39 39
40 void ShowNormalKeyboard(QPoint pos, QSize size); 40 void ShowNormalKeyboard(QPoint pos, QSize size);
41 41
42 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 42 void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
43 std::u16string text_check_message); 43 std::u16string text_check_message);
44 44
45 void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos, 45 void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos,
@@ -52,10 +52,10 @@ public:
52 void ExitKeyboard(); 52 void ExitKeyboard();
53 53
54signals: 54signals:
55 void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, 55 void SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text,
56 bool confirmed = false) const; 56 bool confirmed = false) const;
57 57
58 void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, 58 void SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type,
59 std::u16string submitted_text, s32 cursor_position) const; 59 std::u16string submitted_text, s32 cursor_position) const;
60 60
61public slots: 61public slots:
@@ -244,7 +244,7 @@ public:
244 244
245 void ShowNormalKeyboard() const override; 245 void ShowNormalKeyboard() const override;
246 246
247 void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 247 void ShowTextCheckDialog(Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
248 std::u16string text_check_message) const override; 248 std::u16string text_check_message) const override;
249 249
250 void ShowInlineKeyboard( 250 void ShowInlineKeyboard(
@@ -262,8 +262,9 @@ signals:
262 262
263 void MainWindowShowNormalKeyboard() const; 263 void MainWindowShowNormalKeyboard() const;
264 264
265 void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 265 void MainWindowShowTextCheckDialog(
266 std::u16string text_check_message) const; 266 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
267 std::u16string text_check_message) const;
267 268
268 void MainWindowShowInlineKeyboard( 269 void MainWindowShowInlineKeyboard(
269 Core::Frontend::InlineAppearParameters appear_parameters) const; 270 Core::Frontend::InlineAppearParameters appear_parameters) const;
@@ -275,10 +276,10 @@ signals:
275 void MainWindowExitKeyboard() const; 276 void MainWindowExitKeyboard() const;
276 277
277private: 278private:
278 void SubmitNormalText(Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, 279 void SubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text,
279 bool confirmed) const; 280 bool confirmed) const;
280 281
281 void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, 282 void SubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type,
282 std::u16string submitted_text, s32 cursor_position) const; 283 std::u16string submitted_text, s32 cursor_position) const;
283 284
284 mutable SubmitNormalCallback submit_normal_callback; 285 mutable SubmitNormalCallback submit_normal_callback;
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp
index 34c5fd3be..cce9b2efb 100644
--- a/src/yuzu/applets/qt_web_browser.cpp
+++ b/src/yuzu/applets/qt_web_browser.cpp
@@ -96,7 +96,7 @@ QtNXWebEngineView::QtNXWebEngineView(QWidget* parent, Core::System& system,
96 [this] { 96 [this] {
97 if (page()->url() == url_interceptor->GetRequestedURL()) { 97 if (page()->url() == url_interceptor->GetRequestedURL()) {
98 SetFinished(true); 98 SetFinished(true);
99 SetExitReason(Service::AM::Applets::WebExitReason::WindowClosed); 99 SetExitReason(Service::AM::Frontend::WebExitReason::WindowClosed);
100 } 100 }
101 }, 101 },
102 Qt::QueuedConnection); 102 Qt::QueuedConnection);
@@ -115,7 +115,7 @@ void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url,
115 FocusFirstLinkElement(); 115 FocusFirstLinkElement();
116 SetUserAgent(UserAgent::WebApplet); 116 SetUserAgent(UserAgent::WebApplet);
117 SetFinished(false); 117 SetFinished(false);
118 SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); 118 SetExitReason(Service::AM::Frontend::WebExitReason::EndButtonPressed);
119 SetLastURL("http://localhost/"); 119 SetLastURL("http://localhost/");
120 StartInputThread(); 120 StartInputThread();
121 121
@@ -130,7 +130,7 @@ void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url,
130 FocusFirstLinkElement(); 130 FocusFirstLinkElement();
131 SetUserAgent(UserAgent::WebApplet); 131 SetUserAgent(UserAgent::WebApplet);
132 SetFinished(false); 132 SetFinished(false);
133 SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); 133 SetExitReason(Service::AM::Frontend::WebExitReason::EndButtonPressed);
134 SetLastURL("http://localhost/"); 134 SetLastURL("http://localhost/");
135 StartInputThread(); 135 StartInputThread();
136 136
@@ -170,11 +170,11 @@ void QtNXWebEngineView::SetFinished(bool finished_) {
170 finished = finished_; 170 finished = finished_;
171} 171}
172 172
173Service::AM::Applets::WebExitReason QtNXWebEngineView::GetExitReason() const { 173Service::AM::Frontend::WebExitReason QtNXWebEngineView::GetExitReason() const {
174 return exit_reason; 174 return exit_reason;
175} 175}
176 176
177void QtNXWebEngineView::SetExitReason(Service::AM::Applets::WebExitReason exit_reason_) { 177void QtNXWebEngineView::SetExitReason(Service::AM::Frontend::WebExitReason exit_reason_) {
178 exit_reason = exit_reason_; 178 exit_reason = exit_reason_;
179} 179}
180 180
@@ -441,7 +441,7 @@ void QtWebBrowser::MainWindowExtractOfflineRomFS() {
441 extract_romfs_callback(); 441 extract_romfs_callback();
442} 442}
443 443
444void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, 444void QtWebBrowser::MainWindowWebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason,
445 std::string last_url) { 445 std::string last_url) {
446 if (callback) { 446 if (callback) {
447 callback(exit_reason, last_url); 447 callback(exit_reason, last_url);
diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h
index 1234108ae..e8a0b6931 100644
--- a/src/yuzu/applets/qt_web_browser.h
+++ b/src/yuzu/applets/qt_web_browser.h
@@ -85,8 +85,8 @@ public:
85 [[nodiscard]] bool IsFinished() const; 85 [[nodiscard]] bool IsFinished() const;
86 void SetFinished(bool finished_); 86 void SetFinished(bool finished_);
87 87
88 [[nodiscard]] Service::AM::Applets::WebExitReason GetExitReason() const; 88 [[nodiscard]] Service::AM::Frontend::WebExitReason GetExitReason() const;
89 void SetExitReason(Service::AM::Applets::WebExitReason exit_reason_); 89 void SetExitReason(Service::AM::Frontend::WebExitReason exit_reason_);
90 90
91 [[nodiscard]] const std::string& GetLastURL() const; 91 [[nodiscard]] const std::string& GetLastURL() const;
92 void SetLastURL(std::string last_url_); 92 void SetLastURL(std::string last_url_);
@@ -176,8 +176,8 @@ private:
176 176
177 std::atomic<bool> finished{}; 177 std::atomic<bool> finished{};
178 178
179 Service::AM::Applets::WebExitReason exit_reason{ 179 Service::AM::Frontend::WebExitReason exit_reason{
180 Service::AM::Applets::WebExitReason::EndButtonPressed}; 180 Service::AM::Frontend::WebExitReason::EndButtonPressed};
181 181
182 std::string last_url{"http://localhost/"}; 182 std::string last_url{"http://localhost/"};
183 183
@@ -212,7 +212,7 @@ signals:
212private: 212private:
213 void MainWindowExtractOfflineRomFS(); 213 void MainWindowExtractOfflineRomFS();
214 214
215 void MainWindowWebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, 215 void MainWindowWebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason,
216 std::string last_url); 216 std::string last_url);
217 217
218 mutable ExtractROMFSCallback extract_romfs_callback; 218 mutable ExtractROMFSCallback extract_romfs_callback;
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index 9b6ef47a7..c235b0fca 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -5,6 +5,7 @@
5#include <memory> 5#include <memory>
6#include <vector> 6#include <vector>
7#include <QComboBox> 7#include <QComboBox>
8#include <QPushButton>
8 9
9#include "audio_core/sink/sink.h" 10#include "audio_core/sink/sink.h"
10#include "audio_core/sink/sink_details.h" 11#include "audio_core/sink/sink_details.h"
@@ -67,19 +68,99 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
67 68
68 hold.emplace(std::pair{setting->Id(), widget}); 69 hold.emplace(std::pair{setting->Id(), widget});
69 70
71 auto global_sink_match = [this] {
72 return static_cast<Settings::AudioEngine>(sink_combo_box->currentIndex()) ==
73 Settings::values.sink_id.GetValue(true);
74 };
70 if (setting->Id() == Settings::values.sink_id.Id()) { 75 if (setting->Id() == Settings::values.sink_id.Id()) {
71 // TODO (lat9nq): Let the system manage sink_id 76 // TODO (lat9nq): Let the system manage sink_id
72 sink_combo_box = widget->combobox; 77 sink_combo_box = widget->combobox;
73 InitializeAudioSinkComboBox(); 78 InitializeAudioSinkComboBox();
74 79
75 connect(sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this, 80 if (Settings::IsConfiguringGlobal()) {
76 &ConfigureAudio::UpdateAudioDevices); 81 connect(sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
82 &ConfigureAudio::UpdateAudioDevices);
83 } else {
84 restore_sink_button = ConfigurationShared::Widget::CreateRestoreGlobalButton(
85 Settings::values.sink_id.UsingGlobal(), widget);
86 widget->layout()->addWidget(restore_sink_button);
87 connect(restore_sink_button, &QAbstractButton::clicked, [this](bool) {
88 Settings::values.sink_id.SetGlobal(true);
89 const int sink_index = static_cast<int>(Settings::values.sink_id.GetValue());
90 sink_combo_box->setCurrentIndex(sink_index);
91 ConfigureAudio::UpdateAudioDevices(sink_index);
92 Settings::values.audio_output_device_id.SetGlobal(true);
93 Settings::values.audio_input_device_id.SetGlobal(true);
94 restore_sink_button->setVisible(false);
95 });
96 connect(sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged),
97 [this, global_sink_match](const int slot) {
98 Settings::values.sink_id.SetGlobal(false);
99 Settings::values.audio_output_device_id.SetGlobal(false);
100 Settings::values.audio_input_device_id.SetGlobal(false);
101
102 restore_sink_button->setVisible(true);
103 restore_sink_button->setEnabled(true);
104 output_device_combo_box->setCurrentIndex(0);
105 restore_output_device_button->setVisible(true);
106 restore_output_device_button->setEnabled(global_sink_match());
107 input_device_combo_box->setCurrentIndex(0);
108 restore_input_device_button->setVisible(true);
109 restore_input_device_button->setEnabled(global_sink_match());
110 ConfigureAudio::UpdateAudioDevices(slot);
111 });
112 }
77 } else if (setting->Id() == Settings::values.audio_output_device_id.Id()) { 113 } else if (setting->Id() == Settings::values.audio_output_device_id.Id()) {
78 // Keep track of output (and input) device comboboxes to populate them with system 114 // Keep track of output (and input) device comboboxes to populate them with system
79 // devices, which are determined at run time 115 // devices, which are determined at run time
80 output_device_combo_box = widget->combobox; 116 output_device_combo_box = widget->combobox;
117
118 if (!Settings::IsConfiguringGlobal()) {
119 restore_output_device_button =
120 ConfigurationShared::Widget::CreateRestoreGlobalButton(
121 Settings::values.audio_output_device_id.UsingGlobal(), widget);
122 restore_output_device_button->setEnabled(global_sink_match());
123 restore_output_device_button->setVisible(
124 !Settings::values.audio_output_device_id.UsingGlobal());
125 widget->layout()->addWidget(restore_output_device_button);
126 connect(restore_output_device_button, &QAbstractButton::clicked, [this](bool) {
127 Settings::values.audio_output_device_id.SetGlobal(true);
128 SetOutputDevicesFromDeviceID();
129 restore_output_device_button->setVisible(false);
130 });
131 connect(output_device_combo_box, qOverload<int>(&QComboBox::currentIndexChanged),
132 [this, global_sink_match](int) {
133 if (updating_devices) {
134 return;
135 }
136 Settings::values.audio_output_device_id.SetGlobal(false);
137 restore_output_device_button->setVisible(true);
138 restore_output_device_button->setEnabled(global_sink_match());
139 });
140 }
81 } else if (setting->Id() == Settings::values.audio_input_device_id.Id()) { 141 } else if (setting->Id() == Settings::values.audio_input_device_id.Id()) {
82 input_device_combo_box = widget->combobox; 142 input_device_combo_box = widget->combobox;
143
144 if (!Settings::IsConfiguringGlobal()) {
145 restore_input_device_button =
146 ConfigurationShared::Widget::CreateRestoreGlobalButton(
147 Settings::values.audio_input_device_id.UsingGlobal(), widget);
148 widget->layout()->addWidget(restore_input_device_button);
149 connect(restore_input_device_button, &QAbstractButton::clicked, [this](bool) {
150 Settings::values.audio_input_device_id.SetGlobal(true);
151 SetInputDevicesFromDeviceID();
152 restore_input_device_button->setVisible(false);
153 });
154 connect(input_device_combo_box, qOverload<int>(&QComboBox::currentIndexChanged),
155 [this, global_sink_match](int) {
156 if (updating_devices) {
157 return;
158 }
159 Settings::values.audio_input_device_id.SetGlobal(false);
160 restore_input_device_button->setVisible(true);
161 restore_input_device_button->setEnabled(global_sink_match());
162 });
163 }
83 } 164 }
84 } 165 }
85 166
@@ -89,16 +170,13 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
89} 170}
90 171
91void ConfigureAudio::SetConfiguration() { 172void ConfigureAudio::SetConfiguration() {
92 if (!Settings::IsConfiguringGlobal()) {
93 return;
94 }
95
96 SetOutputSinkFromSinkID(); 173 SetOutputSinkFromSinkID();
97 174
98 // The device list cannot be pre-populated (nor listed) until the output sink is known. 175 // The device list cannot be pre-populated (nor listed) until the output sink is known.
99 UpdateAudioDevices(sink_combo_box->currentIndex()); 176 UpdateAudioDevices(sink_combo_box->currentIndex());
100 177
101 SetAudioDevicesFromDeviceID(); 178 SetOutputDevicesFromDeviceID();
179 SetInputDevicesFromDeviceID();
102} 180}
103 181
104void ConfigureAudio::SetOutputSinkFromSinkID() { 182void ConfigureAudio::SetOutputSinkFromSinkID() {
@@ -116,8 +194,8 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
116 sink_combo_box->setCurrentIndex(new_sink_index); 194 sink_combo_box->setCurrentIndex(new_sink_index);
117} 195}
118 196
119void ConfigureAudio::SetAudioDevicesFromDeviceID() { 197void ConfigureAudio::SetOutputDevicesFromDeviceID() {
120 int new_device_index = -1; 198 int new_device_index = 0;
121 199
122 const QString output_device_id = 200 const QString output_device_id =
123 QString::fromStdString(Settings::values.audio_output_device_id.GetValue()); 201 QString::fromStdString(Settings::values.audio_output_device_id.GetValue());
@@ -129,8 +207,10 @@ void ConfigureAudio::SetAudioDevicesFromDeviceID() {
129 } 207 }
130 208
131 output_device_combo_box->setCurrentIndex(new_device_index); 209 output_device_combo_box->setCurrentIndex(new_device_index);
210}
132 211
133 new_device_index = -1; 212void ConfigureAudio::SetInputDevicesFromDeviceID() {
213 int new_device_index = 0;
134 const QString input_device_id = 214 const QString input_device_id =
135 QString::fromStdString(Settings::values.audio_input_device_id.GetValue()); 215 QString::fromStdString(Settings::values.audio_input_device_id.GetValue());
136 for (int index = 0; index < input_device_combo_box->count(); index++) { 216 for (int index = 0; index < input_device_combo_box->count(); index++) {
@@ -149,15 +229,12 @@ void ConfigureAudio::ApplyConfiguration() {
149 apply_func(is_powered_on); 229 apply_func(is_powered_on);
150 } 230 }
151 231
152 if (Settings::IsConfiguringGlobal()) { 232 Settings::values.sink_id.LoadString(
153 Settings::values.sink_id.LoadString( 233 sink_combo_box->itemText(sink_combo_box->currentIndex()).toStdString());
154 sink_combo_box->itemText(sink_combo_box->currentIndex()).toStdString()); 234 Settings::values.audio_output_device_id.SetValue(
155 Settings::values.audio_output_device_id.SetValue( 235 output_device_combo_box->itemText(output_device_combo_box->currentIndex()).toStdString());
156 output_device_combo_box->itemText(output_device_combo_box->currentIndex()) 236 Settings::values.audio_input_device_id.SetValue(
157 .toStdString()); 237 input_device_combo_box->itemText(input_device_combo_box->currentIndex()).toStdString());
158 Settings::values.audio_input_device_id.SetValue(
159 input_device_combo_box->itemText(input_device_combo_box->currentIndex()).toStdString());
160 }
161} 238}
162 239
163void ConfigureAudio::changeEvent(QEvent* event) { 240void ConfigureAudio::changeEvent(QEvent* event) {
@@ -169,6 +246,7 @@ void ConfigureAudio::changeEvent(QEvent* event) {
169} 246}
170 247
171void ConfigureAudio::UpdateAudioDevices(int sink_index) { 248void ConfigureAudio::UpdateAudioDevices(int sink_index) {
249 updating_devices = true;
172 output_device_combo_box->clear(); 250 output_device_combo_box->clear();
173 output_device_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name)); 251 output_device_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
174 252
@@ -183,6 +261,7 @@ void ConfigureAudio::UpdateAudioDevices(int sink_index) {
183 for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, true)) { 261 for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, true)) {
184 input_device_combo_box->addItem(QString::fromStdString(device)); 262 input_device_combo_box->addItem(QString::fromStdString(device));
185 } 263 }
264 updating_devices = false;
186} 265}
187 266
188void ConfigureAudio::InitializeAudioSinkComboBox() { 267void ConfigureAudio::InitializeAudioSinkComboBox() {
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 82d7f6524..32a2fa5f0 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -45,7 +45,8 @@ private:
45 void UpdateAudioDevices(int sink_index); 45 void UpdateAudioDevices(int sink_index);
46 46
47 void SetOutputSinkFromSinkID(); 47 void SetOutputSinkFromSinkID();
48 void SetAudioDevicesFromDeviceID(); 48 void SetOutputDevicesFromDeviceID();
49 void SetInputDevicesFromDeviceID();
49 50
50 void Setup(const ConfigurationShared::Builder& builder); 51 void Setup(const ConfigurationShared::Builder& builder);
51 52
@@ -55,7 +56,11 @@ private:
55 56
56 std::vector<std::function<void(bool)>> apply_funcs{}; 57 std::vector<std::function<void(bool)>> apply_funcs{};
57 58
59 bool updating_devices = false;
58 QComboBox* sink_combo_box; 60 QComboBox* sink_combo_box;
61 QPushButton* restore_sink_button;
59 QComboBox* output_device_combo_box; 62 QComboBox* output_device_combo_box;
63 QPushButton* restore_output_device_button;
60 QComboBox* input_device_combo_box; 64 QComboBox* input_device_combo_box;
65 QPushButton* restore_input_device_button;
61}; 66};
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 49ec52546..e28df10bd 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -9,6 +9,8 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/service/am/am.h" 10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applet_ae.h" 11#include "core/hle/service/am/applet_ae.h"
12#include "core/hle/service/am/applet_manager.h"
13#include "core/hle/service/am/applet_message_queue.h"
12#include "core/hle/service/am/applet_oe.h" 14#include "core/hle/service/am/applet_oe.h"
13#include "core/hle/service/sm/sm.h" 15#include "core/hle/service/sm/sm.h"
14#include "hid_core/frontend/emulated_controller.h" 16#include "hid_core/frontend/emulated_controller.h"
@@ -47,22 +49,8 @@ void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system)
47 if (!system.IsPoweredOn()) { 49 if (!system.IsPoweredOn()) {
48 return; 50 return;
49 } 51 }
50 Service::SM::ServiceManager& sm = system.ServiceManager();
51 52
52 // Message queue is shared between these services, we just need to signal an operation 53 system.GetAppletManager().OperationModeChanged();
53 // change to one and it will handle both automatically
54 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
55 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
56 bool has_signalled = false;
57
58 if (applet_oe != nullptr) {
59 applet_oe->GetMessageQueue()->OperationModeChanged();
60 has_signalled = true;
61 }
62
63 if (applet_ae != nullptr && !has_signalled) {
64 applet_ae->GetMessageQueue()->OperationModeChanged();
65 }
66} 54}
67 55
68ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) 56ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent)
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 59b317135..b40af957c 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -596,14 +596,10 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri
596 connect(open_save_location, &QAction::triggered, [this, program_id, path]() { 596 connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
597 emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path); 597 emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData, path);
598 }); 598 });
599 connect(start_game, &QAction::triggered, [this, path]() { 599 connect(start_game, &QAction::triggered,
600 emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Normal, 600 [this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Normal); });
601 AmLaunchType::UserInitiated); 601 connect(start_game_global, &QAction::triggered,
602 }); 602 [this, path]() { emit BootGame(QString::fromStdString(path), StartGameType::Global); });
603 connect(start_game_global, &QAction::triggered, [this, path]() {
604 emit BootGame(QString::fromStdString(path), 0, 0, StartGameType::Global,
605 AmLaunchType::UserInitiated);
606 });
607 connect(open_mod_location, &QAction::triggered, [this, program_id, path]() { 603 connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
608 emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path); 604 emit OpenFolderRequested(program_id, GameListOpenTarget::ModData, path);
609 }); 605 });
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 563a3a35b..79f9c7ec0 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -106,8 +106,7 @@ public:
106 static const QStringList supported_file_extensions; 106 static const QStringList supported_file_extensions;
107 107
108signals: 108signals:
109 void BootGame(const QString& game_path, u64 program_id, std::size_t program_index, 109 void BootGame(const QString& game_path, StartGameType type);
110 StartGameType type, AmLaunchType launch_type);
111 void GameChosen(const QString& game_path, const u64 title_id = 0); 110 void GameChosen(const QString& game_path, const u64 title_id = 0);
112 void OpenFolderRequested(u64 program_id, GameListOpenTarget target, 111 void OpenFolderRequested(u64 program_id, GameListOpenTarget target,
113 const std::string& game_path); 112 const std::string& game_path);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 782bcbb61..303d84a1f 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -8,6 +8,7 @@
8#include <iostream> 8#include <iostream>
9#include <memory> 9#include <memory>
10#include <thread> 10#include <thread>
11#include "core/hle/service/am/applet_manager.h"
11#include "core/loader/nca.h" 12#include "core/loader/nca.h"
12#include "core/tools/renderdoc.h" 13#include "core/tools/renderdoc.h"
13 14
@@ -39,13 +40,14 @@
39#include "core/file_sys/vfs/vfs_real.h" 40#include "core/file_sys/vfs/vfs_real.h"
40#include "core/frontend/applets/cabinet.h" 41#include "core/frontend/applets/cabinet.h"
41#include "core/frontend/applets/controller.h" 42#include "core/frontend/applets/controller.h"
42#include "core/frontend/applets/general_frontend.h" 43#include "core/frontend/applets/general.h"
43#include "core/frontend/applets/mii_edit.h" 44#include "core/frontend/applets/mii_edit.h"
44#include "core/frontend/applets/software_keyboard.h" 45#include "core/frontend/applets/software_keyboard.h"
45#include "core/hle/service/acc/profile_manager.h" 46#include "core/hle/service/acc/profile_manager.h"
46#include "core/hle/service/am/applet_ae.h" 47#include "core/hle/service/am/applet_ae.h"
48#include "core/hle/service/am/applet_message_queue.h"
47#include "core/hle/service/am/applet_oe.h" 49#include "core/hle/service/am/applet_oe.h"
48#include "core/hle/service/am/applets/applets.h" 50#include "core/hle/service/am/frontend/applets.h"
49#include "core/hle/service/set/system_settings_server.h" 51#include "core/hle/service/set/system_settings_server.h"
50#include "frontend_common/content_manager.h" 52#include "frontend_common/content_manager.h"
51#include "hid_core/frontend/emulated_controller.h" 53#include "hid_core/frontend/emulated_controller.h"
@@ -568,7 +570,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
568 } 570 }
569 571
570 if (!game_path.isEmpty()) { 572 if (!game_path.isEmpty()) {
571 BootGame(game_path); 573 BootGame(game_path, ApplicationAppletParameters());
572 } 574 }
573} 575}
574 576
@@ -630,13 +632,14 @@ void GMainWindow::RegisterMetaTypes() {
630 qRegisterMetaType<Core::Frontend::InlineAppearParameters>( 632 qRegisterMetaType<Core::Frontend::InlineAppearParameters>(
631 "Core::Frontend::InlineAppearParameters"); 633 "Core::Frontend::InlineAppearParameters");
632 qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters"); 634 qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters");
633 qRegisterMetaType<Service::AM::Applets::SwkbdResult>("Service::AM::Applets::SwkbdResult"); 635 qRegisterMetaType<Service::AM::Frontend::SwkbdResult>("Service::AM::Frontend::SwkbdResult");
634 qRegisterMetaType<Service::AM::Applets::SwkbdTextCheckResult>( 636 qRegisterMetaType<Service::AM::Frontend::SwkbdTextCheckResult>(
635 "Service::AM::Applets::SwkbdTextCheckResult"); 637 "Service::AM::Frontend::SwkbdTextCheckResult");
636 qRegisterMetaType<Service::AM::Applets::SwkbdReplyType>("Service::AM::Applets::SwkbdReplyType"); 638 qRegisterMetaType<Service::AM::Frontend::SwkbdReplyType>(
639 "Service::AM::Frontend::SwkbdReplyType");
637 640
638 // Web Browser Applet 641 // Web Browser Applet
639 qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason"); 642 qRegisterMetaType<Service::AM::Frontend::WebExitReason>("Service::AM::Frontend::WebExitReason");
640 643
641 // Register loader types 644 // Register loader types
642 qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus"); 645 qRegisterMetaType<Core::SystemResultStatus>("Core::SystemResultStatus");
@@ -746,7 +749,7 @@ void GMainWindow::SoftwareKeyboardInitialize(
746 if (is_inline) { 749 if (is_inline) {
747 connect( 750 connect(
748 software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this, 751 software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this,
749 [this](Service::AM::Applets::SwkbdReplyType reply_type, std::u16string submitted_text, 752 [this](Service::AM::Frontend::SwkbdReplyType reply_type, std::u16string submitted_text,
750 s32 cursor_position) { 753 s32 cursor_position) {
751 emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position); 754 emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position);
752 }, 755 },
@@ -754,7 +757,7 @@ void GMainWindow::SoftwareKeyboardInitialize(
754 } else { 757 } else {
755 connect( 758 connect(
756 software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this, 759 software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this,
757 [this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text, 760 [this](Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text,
758 bool confirmed) { 761 bool confirmed) {
759 emit SoftwareKeyboardSubmitNormalText(result, submitted_text, confirmed); 762 emit SoftwareKeyboardSubmitNormalText(result, submitted_text, confirmed);
760 }, 763 },
@@ -781,7 +784,7 @@ void GMainWindow::SoftwareKeyboardShowNormal() {
781} 784}
782 785
783void GMainWindow::SoftwareKeyboardShowTextCheck( 786void GMainWindow::SoftwareKeyboardShowTextCheck(
784 Service::AM::Applets::SwkbdTextCheckResult text_check_result, 787 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
785 std::u16string text_check_message) { 788 std::u16string text_check_message) {
786 if (!software_keyboard) { 789 if (!software_keyboard) {
787 LOG_ERROR(Frontend, "The software keyboard is not initialized!"); 790 LOG_ERROR(Frontend, "The software keyboard is not initialized!");
@@ -852,7 +855,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
852 855
853 // Raw input breaks with the web applet, Disable web applets if enabled 856 // Raw input breaks with the web applet, Disable web applets if enabled
854 if (UISettings::values.disable_web_applet || Settings::values.enable_raw_input) { 857 if (UISettings::values.disable_web_applet || Settings::values.enable_raw_input) {
855 emit WebBrowserClosed(Service::AM::Applets::WebExitReason::WindowClosed, 858 emit WebBrowserClosed(Service::AM::Frontend::WebExitReason::WindowClosed,
856 "http://localhost/"); 859 "http://localhost/");
857 return; 860 return;
858 } 861 }
@@ -940,7 +943,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
940 if (variant.toBool()) { 943 if (variant.toBool()) {
941 web_applet->SetFinished(true); 944 web_applet->SetFinished(true);
942 web_applet->SetExitReason( 945 web_applet->SetExitReason(
943 Service::AM::Applets::WebExitReason::EndButtonPressed); 946 Service::AM::Frontend::WebExitReason::EndButtonPressed);
944 } 947 }
945 }); 948 });
946 949
@@ -950,7 +953,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
950 if (web_applet->GetCurrentURL().contains(QStringLiteral("localhost"))) { 953 if (web_applet->GetCurrentURL().contains(QStringLiteral("localhost"))) {
951 if (!web_applet->IsFinished()) { 954 if (!web_applet->IsFinished()) {
952 web_applet->SetFinished(true); 955 web_applet->SetFinished(true);
953 web_applet->SetExitReason(Service::AM::Applets::WebExitReason::CallbackURL); 956 web_applet->SetExitReason(Service::AM::Frontend::WebExitReason::CallbackURL);
954 } 957 }
955 958
956 web_applet->SetLastURL(web_applet->GetCurrentURL().toStdString()); 959 web_applet->SetLastURL(web_applet->GetCurrentURL().toStdString());
@@ -983,7 +986,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
983#else 986#else
984 987
985 // Utilize the same fallback as the default web browser applet. 988 // Utilize the same fallback as the default web browser applet.
986 emit WebBrowserClosed(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/"); 989 emit WebBrowserClosed(Service::AM::Frontend::WebExitReason::WindowClosed, "http://localhost/");
987 990
988#endif 991#endif
989} 992}
@@ -991,7 +994,7 @@ void GMainWindow::WebBrowserOpenWebPage(const std::string& main_url,
991void GMainWindow::WebBrowserRequestExit() { 994void GMainWindow::WebBrowserRequestExit() {
992#ifdef YUZU_USE_QT_WEB_ENGINE 995#ifdef YUZU_USE_QT_WEB_ENGINE
993 if (web_applet) { 996 if (web_applet) {
994 web_applet->SetExitReason(Service::AM::Applets::WebExitReason::ExitRequested); 997 web_applet->SetExitReason(Service::AM::Frontend::WebExitReason::ExitRequested);
995 web_applet->SetFinished(true); 998 web_applet->SetFinished(true);
996 } 999 }
997#endif 1000#endif
@@ -1472,7 +1475,7 @@ void GMainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
1472} 1475}
1473 1476
1474void GMainWindow::ConnectWidgetEvents() { 1477void GMainWindow::ConnectWidgetEvents() {
1475 connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGame); 1478 connect(game_list, &GameList::BootGame, this, &GMainWindow::BootGameFromList);
1476 connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile); 1479 connect(game_list, &GameList::GameChosen, this, &GMainWindow::OnGameListLoadFile);
1477 connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory); 1480 connect(game_list, &GameList::OpenDirectory, this, &GMainWindow::OnGameListOpenDirectory);
1478 connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); 1481 connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
@@ -1760,8 +1763,7 @@ void GMainWindow::AllowOSSleep() {
1760#endif 1763#endif
1761} 1764}
1762 1765
1763bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t program_index, 1766bool GMainWindow::LoadROM(const QString& filename, Service::AM::FrontendAppletParameters params) {
1764 AmLaunchType launch_type) {
1765 // Shutdown previous session if the emu thread is still active... 1767 // Shutdown previous session if the emu thread is still active...
1766 if (emu_thread != nullptr) { 1768 if (emu_thread != nullptr) {
1767 ShutdownGame(); 1769 ShutdownGame();
@@ -1773,11 +1775,11 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1773 1775
1774 system->SetFilesystem(vfs); 1776 system->SetFilesystem(vfs);
1775 1777
1776 if (launch_type == AmLaunchType::UserInitiated) { 1778 if (params.launch_type == Service::AM::LaunchType::FrontendInitiated) {
1777 system->GetUserChannel().clear(); 1779 system->GetUserChannel().clear();
1778 } 1780 }
1779 1781
1780 system->SetAppletFrontendSet({ 1782 system->SetFrontendAppletSet({
1781 std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings 1783 std::make_unique<QtAmiiboSettings>(*this), // Amiibo Settings
1782 (UISettings::values.controller_applet_disabled.GetValue() == true) 1784 (UISettings::values.controller_applet_disabled.GetValue() == true)
1783 ? nullptr 1785 ? nullptr
@@ -1792,7 +1794,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1792 }); 1794 });
1793 1795
1794 const Core::SystemResultStatus result{ 1796 const Core::SystemResultStatus result{
1795 system->Load(*render_window, filename.toStdString(), program_id, program_index)}; 1797 system->Load(*render_window, filename.toStdString(), params)};
1796 1798
1797 const auto drd_callout = (UISettings::values.callout_flags.GetValue() & 1799 const auto drd_callout = (UISettings::values.callout_flags.GetValue() &
1798 static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; 1800 static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0;
@@ -1915,12 +1917,12 @@ void GMainWindow::ConfigureFilesystemProvider(const std::string& filepath) {
1915 } 1917 }
1916} 1918}
1917 1919
1918void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t program_index, 1920void GMainWindow::BootGame(const QString& filename, Service::AM::FrontendAppletParameters params,
1919 StartGameType type, AmLaunchType launch_type) { 1921 StartGameType type) {
1920 LOG_INFO(Frontend, "yuzu starting..."); 1922 LOG_INFO(Frontend, "yuzu starting...");
1921 1923
1922 if (program_id == 0 || 1924 if (params.program_id == 0 ||
1923 program_id > static_cast<u64>(Service::AM::Applets::AppletProgramId::MaxProgramId)) { 1925 params.program_id > static_cast<u64>(Service::AM::AppletProgramId::MaxProgramId)) {
1924 StoreRecentFile(filename); // Put the filename on top of the list 1926 StoreRecentFile(filename); // Put the filename on top of the list
1925 } 1927 }
1926 1928
@@ -1935,7 +1937,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1935 1937
1936 ConfigureFilesystemProvider(filename.toStdString()); 1938 ConfigureFilesystemProvider(filename.toStdString());
1937 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); 1939 const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData());
1938 const auto loader = Loader::GetLoader(*system, v_file, program_id, program_index); 1940 const auto loader = Loader::GetLoader(*system, v_file, params.program_id, params.program_index);
1939 1941
1940 if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success && 1942 if (loader != nullptr && loader->ReadProgramId(title_id) == Loader::ResultStatus::Success &&
1941 type == StartGameType::Normal) { 1943 type == StartGameType::Normal) {
@@ -1954,10 +1956,10 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1954 1956
1955 if (UISettings::values.select_user_on_boot && !user_flag_cmd_line) { 1957 if (UISettings::values.select_user_on_boot && !user_flag_cmd_line) {
1956 const Core::Frontend::ProfileSelectParameters parameters{ 1958 const Core::Frontend::ProfileSelectParameters parameters{
1957 .mode = Service::AM::Applets::UiMode::UserSelector, 1959 .mode = Service::AM::Frontend::UiMode::UserSelector,
1958 .invalid_uid_list = {}, 1960 .invalid_uid_list = {},
1959 .display_options = {}, 1961 .display_options = {},
1960 .purpose = Service::AM::Applets::UserSelectionPurpose::General, 1962 .purpose = Service::AM::Frontend::UserSelectionPurpose::General,
1961 }; 1963 };
1962 if (SelectAndSetCurrentUser(parameters) == false) { 1964 if (SelectAndSetCurrentUser(parameters) == false) {
1963 return; 1965 return;
@@ -1969,7 +1971,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1969 // behavior of asking. 1971 // behavior of asking.
1970 user_flag_cmd_line = false; 1972 user_flag_cmd_line = false;
1971 1973
1972 if (!LoadROM(filename, program_id, program_index, launch_type)) { 1974 if (!LoadROM(filename, params)) {
1973 return; 1975 return;
1974 } 1976 }
1975 1977
@@ -2059,6 +2061,10 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
2059 OnStartGame(); 2061 OnStartGame();
2060} 2062}
2061 2063
2064void GMainWindow::BootGameFromList(const QString& filename, StartGameType with_config) {
2065 BootGame(filename, ApplicationAppletParameters(), with_config);
2066}
2067
2062bool GMainWindow::OnShutdownBegin() { 2068bool GMainWindow::OnShutdownBegin() {
2063 if (!emulation_running) { 2069 if (!emulation_running) {
2064 return false; 2070 return false;
@@ -2160,7 +2166,7 @@ void GMainWindow::OnEmulationStopped() {
2160 OnTasStateChanged(); 2166 OnTasStateChanged();
2161 render_window->FinalizeCamera(); 2167 render_window->FinalizeCamera();
2162 2168
2163 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::None); 2169 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::None);
2164 2170
2165 // Enable all controllers 2171 // Enable all controllers
2166 system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All}); 2172 system->HIDCore().SetSupportedStyleTag({Core::HID::NpadStyleSet::All});
@@ -2239,7 +2245,10 @@ void GMainWindow::UpdateRecentFiles() {
2239} 2245}
2240 2246
2241void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) { 2247void GMainWindow::OnGameListLoadFile(QString game_path, u64 program_id) {
2242 BootGame(game_path, program_id); 2248 auto params = ApplicationAppletParameters();
2249 params.program_id = program_id;
2250
2251 BootGame(game_path, params);
2243} 2252}
2244 2253
2245void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, 2254void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target,
@@ -2280,10 +2289,10 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
2280 // User save data 2289 // User save data
2281 const auto select_profile = [this] { 2290 const auto select_profile = [this] {
2282 const Core::Frontend::ProfileSelectParameters parameters{ 2291 const Core::Frontend::ProfileSelectParameters parameters{
2283 .mode = Service::AM::Applets::UiMode::UserSelector, 2292 .mode = Service::AM::Frontend::UiMode::UserSelector,
2284 .invalid_uid_list = {}, 2293 .invalid_uid_list = {},
2285 .display_options = {}, 2294 .display_options = {},
2286 .purpose = Service::AM::Applets::UserSelectionPurpose::General, 2295 .purpose = Service::AM::Frontend::UserSelectionPurpose::General,
2287 }; 2296 };
2288 QtProfileSelectionDialog dialog(*system, this, parameters); 2297 QtProfileSelectionDialog dialog(*system, this, parameters);
2289 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | 2298 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
@@ -3171,7 +3180,7 @@ void GMainWindow::OnMenuLoadFile() {
3171 } 3180 }
3172 3181
3173 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 3182 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
3174 BootGame(filename); 3183 BootGame(filename, ApplicationAppletParameters());
3175} 3184}
3176 3185
3177void GMainWindow::OnMenuLoadFolder() { 3186void GMainWindow::OnMenuLoadFolder() {
@@ -3185,7 +3194,7 @@ void GMainWindow::OnMenuLoadFolder() {
3185 const QDir dir{dir_path}; 3194 const QDir dir{dir_path};
3186 const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files); 3195 const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files);
3187 if (matching_main.size() == 1) { 3196 if (matching_main.size() == 1) {
3188 BootGame(dir.path() + QDir::separator() + matching_main[0]); 3197 BootGame(dir.path() + QDir::separator() + matching_main[0], ApplicationAppletParameters());
3189 } else { 3198 } else {
3190 QMessageBox::warning(this, tr("Invalid Directory Selected"), 3199 QMessageBox::warning(this, tr("Invalid Directory Selected"),
3191 tr("The directory you have selected does not contain a 'main' file.")); 3200 tr("The directory you have selected does not contain a 'main' file."));
@@ -3379,7 +3388,7 @@ void GMainWindow::OnMenuRecentFile() {
3379 3388
3380 const QString filename = action->data().toString(); 3389 const QString filename = action->data().toString();
3381 if (QFileInfo::exists(filename)) { 3390 if (QFileInfo::exists(filename)) {
3382 BootGame(filename); 3391 BootGame(filename, ApplicationAppletParameters());
3383 } else { 3392 } else {
3384 // Display an error message and remove the file from the list. 3393 // Display an error message and remove the file from the list.
3385 QMessageBox::information(this, tr("File not found"), 3394 QMessageBox::information(this, tr("File not found"),
@@ -3417,7 +3426,7 @@ void GMainWindow::OnRestartGame() {
3417 // Make a copy since ShutdownGame edits game_path 3426 // Make a copy since ShutdownGame edits game_path
3418 const auto current_game = QString(current_game_path); 3427 const auto current_game = QString(current_game_path);
3419 ShutdownGame(); 3428 ShutdownGame();
3420 BootGame(current_game); 3429 BootGame(current_game, ApplicationAppletParameters());
3421 } 3430 }
3422} 3431}
3423 3432
@@ -3485,8 +3494,11 @@ void GMainWindow::OnLoadComplete() {
3485 3494
3486void GMainWindow::OnExecuteProgram(std::size_t program_index) { 3495void GMainWindow::OnExecuteProgram(std::size_t program_index) {
3487 ShutdownGame(); 3496 ShutdownGame();
3488 BootGame(last_filename_booted, 0, program_index, StartGameType::Normal, 3497
3489 AmLaunchType::ApplicationInitiated); 3498 auto params = ApplicationAppletParameters();
3499 params.program_index = static_cast<s32>(program_index);
3500 params.launch_type = Service::AM::LaunchType::ApplicationInitiated;
3501 BootGame(last_filename_booted, params);
3490} 3502}
3491 3503
3492void GMainWindow::OnExit() { 3504void GMainWindow::OnExit() {
@@ -4153,7 +4165,7 @@ void GMainWindow::OnToggleStatusBar() {
4153} 4165}
4154 4166
4155void GMainWindow::OnAlbum() { 4167void GMainWindow::OnAlbum() {
4156 constexpr u64 AlbumId = static_cast<u64>(Service::AM::Applets::AppletProgramId::PhotoViewer); 4168 constexpr u64 AlbumId = static_cast<u64>(Service::AM::AppletProgramId::PhotoViewer);
4157 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4169 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4158 if (!bis_system) { 4170 if (!bis_system) {
4159 QMessageBox::warning(this, tr("No firmware available"), 4171 QMessageBox::warning(this, tr("No firmware available"),
@@ -4168,15 +4180,15 @@ void GMainWindow::OnAlbum() {
4168 return; 4180 return;
4169 } 4181 }
4170 4182
4171 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::PhotoViewer); 4183 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::PhotoViewer);
4172 4184
4173 const auto filename = QString::fromStdString(album_nca->GetFullPath()); 4185 const auto filename = QString::fromStdString(album_nca->GetFullPath());
4174 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 4186 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4175 BootGame(filename, AlbumId); 4187 BootGame(filename, LibraryAppletParameters(AlbumId, Service::AM::AppletId::PhotoViewer));
4176} 4188}
4177 4189
4178void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) { 4190void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
4179 constexpr u64 CabinetId = static_cast<u64>(Service::AM::Applets::AppletProgramId::Cabinet); 4191 constexpr u64 CabinetId = static_cast<u64>(Service::AM::AppletProgramId::Cabinet);
4180 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4192 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4181 if (!bis_system) { 4193 if (!bis_system) {
4182 QMessageBox::warning(this, tr("No firmware available"), 4194 QMessageBox::warning(this, tr("No firmware available"),
@@ -4191,16 +4203,16 @@ void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
4191 return; 4203 return;
4192 } 4204 }
4193 4205
4194 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Cabinet); 4206 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Cabinet);
4195 system->GetAppletManager().SetCabinetMode(mode); 4207 system->GetFrontendAppletHolder().SetCabinetMode(mode);
4196 4208
4197 const auto filename = QString::fromStdString(cabinet_nca->GetFullPath()); 4209 const auto filename = QString::fromStdString(cabinet_nca->GetFullPath());
4198 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 4210 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4199 BootGame(filename, CabinetId); 4211 BootGame(filename, LibraryAppletParameters(CabinetId, Service::AM::AppletId::Cabinet));
4200} 4212}
4201 4213
4202void GMainWindow::OnMiiEdit() { 4214void GMainWindow::OnMiiEdit() {
4203 constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); 4215 constexpr u64 MiiEditId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit);
4204 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4216 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4205 if (!bis_system) { 4217 if (!bis_system) {
4206 QMessageBox::warning(this, tr("No firmware available"), 4218 QMessageBox::warning(this, tr("No firmware available"),
@@ -4215,16 +4227,15 @@ void GMainWindow::OnMiiEdit() {
4215 return; 4227 return;
4216 } 4228 }
4217 4229
4218 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::MiiEdit); 4230 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit);
4219 4231
4220 const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath())); 4232 const auto filename = QString::fromStdString((mii_applet_nca->GetFullPath()));
4221 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 4233 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4222 BootGame(filename, MiiEditId); 4234 BootGame(filename, LibraryAppletParameters(MiiEditId, Service::AM::AppletId::MiiEdit));
4223} 4235}
4224 4236
4225void GMainWindow::OnOpenControllerMenu() { 4237void GMainWindow::OnOpenControllerMenu() {
4226 constexpr u64 ControllerAppletId = 4238 constexpr u64 ControllerAppletId = static_cast<u64>(Service::AM::AppletProgramId::Controller);
4227 static_cast<u64>(Service::AM::Applets::AppletProgramId::Controller);
4228 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4239 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4229 if (!bis_system) { 4240 if (!bis_system) {
4230 QMessageBox::warning(this, tr("No firmware available"), 4241 QMessageBox::warning(this, tr("No firmware available"),
@@ -4240,11 +4251,12 @@ void GMainWindow::OnOpenControllerMenu() {
4240 return; 4251 return;
4241 } 4252 }
4242 4253
4243 system->GetAppletManager().SetCurrentAppletId(Service::AM::Applets::AppletId::Controller); 4254 system->GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::Controller);
4244 4255
4245 const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath())); 4256 const auto filename = QString::fromStdString((controller_applet_nca->GetFullPath()));
4246 UISettings::values.roms_path = QFileInfo(filename).path().toStdString(); 4257 UISettings::values.roms_path = QFileInfo(filename).path().toStdString();
4247 BootGame(filename, ControllerAppletId); 4258 BootGame(filename,
4259 LibraryAppletParameters(ControllerAppletId, Service::AM::AppletId::Controller));
4248} 4260}
4249 4261
4250void GMainWindow::OnCaptureScreenshot() { 4262void GMainWindow::OnCaptureScreenshot() {
@@ -4564,7 +4576,7 @@ void GMainWindow::OnCheckFirmwareDecryption() {
4564} 4576}
4565 4577
4566bool GMainWindow::CheckFirmwarePresence() { 4578bool GMainWindow::CheckFirmwarePresence() {
4567 constexpr u64 MiiEditId = static_cast<u64>(Service::AM::Applets::AppletProgramId::MiiEdit); 4579 constexpr u64 MiiEditId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit);
4568 4580
4569 auto bis_system = system->GetFileSystemController().GetSystemNANDContents(); 4581 auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
4570 if (!bis_system) { 4582 if (!bis_system) {
@@ -4727,7 +4739,7 @@ bool GMainWindow::DropAction(QDropEvent* event) {
4727 } else { 4739 } else {
4728 // Game 4740 // Game
4729 if (ConfirmChangeGame()) { 4741 if (ConfirmChangeGame()) {
4730 BootGame(filename); 4742 BootGame(filename, ApplicationAppletParameters());
4731 } 4743 }
4732 } 4744 }
4733 return true; 4745 return true;
@@ -4771,36 +4783,12 @@ void GMainWindow::RequestGameExit() {
4771 return; 4783 return;
4772 } 4784 }
4773 4785
4774 auto& sm{system->ServiceManager()};
4775 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
4776 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
4777 bool has_signalled = false;
4778
4779 system->SetExitRequested(true); 4786 system->SetExitRequested(true);
4780 4787 system->GetAppletManager().RequestExit();
4781 if (applet_oe != nullptr) {
4782 applet_oe->GetMessageQueue()->RequestExit();
4783 has_signalled = true;
4784 }
4785
4786 if (applet_ae != nullptr && !has_signalled) {
4787 applet_ae->GetMessageQueue()->RequestExit();
4788 }
4789} 4788}
4790 4789
4791void GMainWindow::RequestGameResume() { 4790void GMainWindow::RequestGameResume() {
4792 auto& sm{system->ServiceManager()}; 4791 system->GetAppletManager().RequestResume();
4793 auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
4794 auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
4795
4796 if (applet_oe != nullptr) {
4797 applet_oe->GetMessageQueue()->RequestResume();
4798 return;
4799 }
4800
4801 if (applet_ae != nullptr) {
4802 applet_ae->GetMessageQueue()->RequestResume();
4803 }
4804} 4792}
4805 4793
4806void GMainWindow::filterBarSetChecked(bool state) { 4794void GMainWindow::filterBarSetChecked(bool state) {
@@ -4942,6 +4930,22 @@ void GMainWindow::changeEvent(QEvent* event) {
4942 QWidget::changeEvent(event); 4930 QWidget::changeEvent(event);
4943} 4931}
4944 4932
4933Service::AM::FrontendAppletParameters GMainWindow::ApplicationAppletParameters() {
4934 return Service::AM::FrontendAppletParameters{
4935 .applet_id = Service::AM::AppletId::Application,
4936 .applet_type = Service::AM::AppletType::Application,
4937 };
4938}
4939
4940Service::AM::FrontendAppletParameters GMainWindow::LibraryAppletParameters(
4941 u64 program_id, Service::AM::AppletId applet_id) {
4942 return Service::AM::FrontendAppletParameters{
4943 .program_id = program_id,
4944 .applet_id = applet_id,
4945 .applet_type = Service::AM::AppletType::LibraryApplet,
4946 };
4947}
4948
4945void VolumeButton::wheelEvent(QWheelEvent* event) { 4949void VolumeButton::wheelEvent(QWheelEvent* event) {
4946 4950
4947 int num_degrees = event->angleDelta().y() / 8; 4951 int num_degrees = event->angleDelta().y() / 8;
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 6b72094ff..aba61e388 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -64,11 +64,6 @@ enum class StartGameType {
64 Global, // Only uses global configuration 64 Global, // Only uses global configuration
65}; 65};
66 66
67enum class AmLaunchType {
68 UserInitiated,
69 ApplicationInitiated,
70};
71
72namespace Core { 67namespace Core {
73enum class SystemResultStatus : u32; 68enum class SystemResultStatus : u32;
74class System; 69class System;
@@ -101,12 +96,17 @@ namespace InputCommon {
101class InputSubsystem; 96class InputSubsystem;
102} 97}
103 98
104namespace Service::AM::Applets { 99namespace Service::AM {
100struct FrontendAppletParameters;
101enum class AppletId : u32;
102} // namespace Service::AM
103
104namespace Service::AM::Frontend {
105enum class SwkbdResult : u32; 105enum class SwkbdResult : u32;
106enum class SwkbdTextCheckResult : u32; 106enum class SwkbdTextCheckResult : u32;
107enum class SwkbdReplyType : u32; 107enum class SwkbdReplyType : u32;
108enum class WebExitReason : u32; 108enum class WebExitReason : u32;
109} // namespace Service::AM::Applets 109} // namespace Service::AM::Frontend
110 110
111namespace Service::NFC { 111namespace Service::NFC {
112class NfcDevice; 112class NfcDevice;
@@ -204,13 +204,13 @@ signals:
204 204
205 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); 205 void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
206 206
207 void SoftwareKeyboardSubmitNormalText(Service::AM::Applets::SwkbdResult result, 207 void SoftwareKeyboardSubmitNormalText(Service::AM::Frontend::SwkbdResult result,
208 std::u16string submitted_text, bool confirmed); 208 std::u16string submitted_text, bool confirmed);
209 void SoftwareKeyboardSubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type, 209 void SoftwareKeyboardSubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type,
210 std::u16string submitted_text, s32 cursor_position); 210 std::u16string submitted_text, s32 cursor_position);
211 211
212 void WebBrowserExtractOfflineRomFS(); 212 void WebBrowserExtractOfflineRomFS();
213 void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); 213 void WebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, std::string last_url);
214 214
215 void SigInterrupt(); 215 void SigInterrupt();
216 216
@@ -228,8 +228,9 @@ public slots:
228 void SoftwareKeyboardInitialize( 228 void SoftwareKeyboardInitialize(
229 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters); 229 bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters);
230 void SoftwareKeyboardShowNormal(); 230 void SoftwareKeyboardShowNormal();
231 void SoftwareKeyboardShowTextCheck(Service::AM::Applets::SwkbdTextCheckResult text_check_result, 231 void SoftwareKeyboardShowTextCheck(
232 std::u16string text_check_message); 232 Service::AM::Frontend::SwkbdTextCheckResult text_check_result,
233 std::u16string text_check_message);
233 void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters); 234 void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters);
234 void SoftwareKeyboardHideInline(); 235 void SoftwareKeyboardHideInline();
235 void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); 236 void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
@@ -267,11 +268,10 @@ private:
267 void PreventOSSleep(); 268 void PreventOSSleep();
268 void AllowOSSleep(); 269 void AllowOSSleep();
269 270
270 bool LoadROM(const QString& filename, u64 program_id, std::size_t program_index, 271 bool LoadROM(const QString& filename, Service::AM::FrontendAppletParameters params);
271 AmLaunchType launch_type); 272 void BootGame(const QString& filename, Service::AM::FrontendAppletParameters params,
272 void BootGame(const QString& filename, u64 program_id = 0, std::size_t program_index = 0, 273 StartGameType with_config = StartGameType::Normal);
273 StartGameType with_config = StartGameType::Normal, 274 void BootGameFromList(const QString& filename, StartGameType with_config);
274 AmLaunchType launch_type = AmLaunchType::UserInitiated);
275 void ShutdownGame(); 275 void ShutdownGame();
276 276
277 void ShowTelemetryCallout(); 277 void ShowTelemetryCallout();
@@ -324,6 +324,10 @@ private:
324 void SetGamemodeEnabled(bool state); 324 void SetGamemodeEnabled(bool state);
325#endif 325#endif
326 326
327 Service::AM::FrontendAppletParameters ApplicationAppletParameters();
328 Service::AM::FrontendAppletParameters LibraryAppletParameters(u64 program_id,
329 Service::AM::AppletId applet_id);
330
327private slots: 331private slots:
328 void OnStartGame(); 332 void OnStartGame();
329 void OnRestartGame(); 333 void OnRestartGame();
diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt
index fbeba8813..ebd8fd738 100644
--- a/src/yuzu_cmd/CMakeLists.txt
+++ b/src/yuzu_cmd/CMakeLists.txt
@@ -28,8 +28,6 @@ add_executable(yuzu-cmd
28 yuzu.rc 28 yuzu.rc
29) 29)
30 30
31create_target_directory_groups(yuzu-cmd)
32
33target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common) 31target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common)
34target_link_libraries(yuzu-cmd PRIVATE glad) 32target_link_libraries(yuzu-cmd PRIVATE glad)
35if (MSVC) 33if (MSVC)
@@ -63,3 +61,5 @@ endif()
63if (YUZU_USE_PRECOMPILED_HEADERS) 61if (YUZU_USE_PRECOMPILED_HEADERS)
64 target_precompile_headers(yuzu-cmd PRIVATE precompiled_headers.h) 62 target_precompile_headers(yuzu-cmd PRIVATE precompiled_headers.h)
65endif() 63endif()
64
65create_target_directory_groups(yuzu-cmd)
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index c39ace2ec..3b321dad1 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -26,6 +26,7 @@
26#include "core/crypto/key_manager.h" 26#include "core/crypto/key_manager.h"
27#include "core/file_sys/registered_cache.h" 27#include "core/file_sys/registered_cache.h"
28#include "core/file_sys/vfs/vfs_real.h" 28#include "core/file_sys/vfs/vfs_real.h"
29#include "core/hle/service/am/applet_manager.h"
29#include "core/hle/service/filesystem/filesystem.h" 30#include "core/hle/service/filesystem/filesystem.h"
30#include "core/loader/loader.h" 31#include "core/loader/loader.h"
31#include "core/telemetry_session.h" 32#include "core/telemetry_session.h"
@@ -366,7 +367,10 @@ int main(int argc, char** argv) {
366 system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); 367 system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
367 system.GetUserChannel().clear(); 368 system.GetUserChannel().clear();
368 369
369 const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath)}; 370 Service::AM::FrontendAppletParameters load_parameters{
371 .applet_id = Service::AM::AppletId::Application,
372 };
373 const Core::SystemResultStatus load_result{system.Load(*emu_window, filepath, load_parameters)};
370 374
371 switch (load_result) { 375 switch (load_result) {
372 case Core::SystemResultStatus::ErrorGetLoader: 376 case Core::SystemResultStatus::ErrorGetLoader: