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/fragments/AddGameFolderDialogFragment.kt3
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt28
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt8
-rw-r--r--src/android/app/src/main/jni/native.cpp7
-rw-r--r--src/android/app/src/main/jni/native.h1
-rw-r--r--src/common/host_memory.cpp38
-rw-r--r--src/common/host_memory.h2
-rw-r--r--src/common/settings.cpp8
-rw-r--r--src/common/settings.h14
-rw-r--r--src/core/CMakeLists.txt26
-rw-r--r--src/core/arm/arm_interface.cpp217
-rw-r--r--src/core/arm/arm_interface.h221
-rw-r--r--src/core/arm/debug.cpp354
-rw-r--r--src/core/arm/debug.h35
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp325
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h92
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp340
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h77
-rw-r--r--src/core/arm/dynarmic/dynarmic_cp15.cpp4
-rw-r--r--src/core/arm/dynarmic/dynarmic_cp15.h8
-rw-r--r--src/core/arm/dynarmic/dynarmic_exclusive_monitor.h8
-rw-r--r--src/core/arm/nce/arm_nce.cpp255
-rw-r--r--src/core/arm/nce/arm_nce.h70
-rw-r--r--src/core/arm/nce/arm_nce.s80
-rw-r--r--src/core/arm/nce/guest_context.h8
-rw-r--r--src/core/arm/nce/patcher.cpp2
-rw-r--r--src/core/core.cpp39
-rw-r--r--src/core/core.h29
-rw-r--r--src/core/cpu_manager.cpp8
-rw-r--r--src/core/debugger/gdbstub.cpp243
-rw-r--r--src/core/debugger/gdbstub_arch.cpp72
-rw-r--r--src/core/debugger/gdbstub_arch.h1
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp134
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.h6
-rw-r--r--src/core/file_sys/romfs.cpp83
-rw-r--r--src/core/file_sys/savedata_factory.cpp6
-rw-r--r--src/core/file_sys/savedata_factory.h4
-rw-r--r--src/core/file_sys/vfs_concat.cpp4
-rw-r--r--src/core/file_sys/vfs_concat.h2
-rw-r--r--src/core/file_sys/vfs_layered.cpp21
-rw-r--r--src/core/hid/input_interpreter.cpp3
-rw-r--r--src/core/hle/kernel/k_client_port.cpp69
-rw-r--r--src/core/hle/kernel/k_client_port.h2
-rw-r--r--src/core/hle/kernel/k_client_session.cpp24
-rw-r--r--src/core/hle/kernel/k_client_session.h18
-rw-r--r--src/core/hle/kernel/k_light_client_session.cpp31
-rw-r--r--src/core/hle/kernel/k_light_client_session.h39
-rw-r--r--src/core/hle/kernel/k_light_server_session.cpp247
-rw-r--r--src/core/hle/kernel/k_light_server_session.h49
-rw-r--r--src/core/hle/kernel/k_light_session.cpp81
-rw-r--r--src/core/hle/kernel/k_light_session.h86
-rw-r--r--src/core/hle/kernel/k_memory_manager.cpp5
-rw-r--r--src/core/hle/kernel/k_page_table_base.cpp32
-rw-r--r--src/core/hle/kernel/k_port.cpp9
-rw-r--r--src/core/hle/kernel/k_port.h2
-rw-r--r--src/core/hle/kernel/k_process.cpp40
-rw-r--r--src/core/hle/kernel/k_process.h9
-rw-r--r--src/core/hle/kernel/k_process_page_table.h4
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp16
-rw-r--r--src/core/hle/kernel/k_server_port.cpp56
-rw-r--r--src/core/hle/kernel/k_server_port.h5
-rw-r--r--src/core/hle/kernel/k_server_session.cpp8
-rw-r--r--src/core/hle/kernel/k_session.h4
-rw-r--r--src/core/hle/kernel/k_thread.cpp80
-rw-r--r--src/core/hle/kernel/k_thread.h36
-rw-r--r--src/core/hle/kernel/kernel.cpp47
-rw-r--r--src/core/hle/kernel/kernel.h13
-rw-r--r--src/core/hle/kernel/physical_core.cpp251
-rw-r--r--src/core/hle/kernel/physical_core.h57
-rw-r--r--src/core/hle/kernel/svc.cpp2955
-rw-r--r--src/core/hle/kernel/svc.h14
-rw-r--r--src/core/hle/kernel/svc/svc_exception.cpp4
-rw-r--r--src/core/hle/kernel/svc/svc_ipc.cpp296
-rw-r--r--src/core/hle/kernel/svc/svc_light_ipc.cpp60
-rw-r--r--src/core/hle/kernel/svc/svc_port.cpp71
-rw-r--r--src/core/hle/kernel/svc/svc_secure_monitor_call.cpp22
-rw-r--r--src/core/hle/kernel/svc/svc_session.cpp40
-rw-r--r--src/core/hle/kernel/svc/svc_thread.cpp50
-rw-r--r--src/core/hle/kernel/svc_generator.py59
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp8
-rw-r--r--src/core/hle/service/hid/controllers/applet_resource.cpp313
-rw-r--r--src/core/hle/service/hid/controllers/applet_resource.h98
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.cpp21
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.h19
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h3
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp23
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h48
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp36
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h90
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp23
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h33
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp19
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h16
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp28
-rw-r--r--src/core/hle/service/hid/controllers/npad.h314
-rw-r--r--src/core/hle/service/hid/controllers/palma.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/palma.h3
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_format.h240
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_holder.cpp53
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_holder.h44
-rw-r--r--src/core/hle/service/hid/controllers/six_axis.cpp25
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp19
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h18
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp24
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h32
-rw-r--r--src/core/hle/service/hid/controllers/types/debug_pad_types.h31
-rw-r--r--src/core/hle/service/hid/controllers/types/gesture_types.h77
-rw-r--r--src/core/hle/service/hid/controllers/types/keyboard_types.h20
-rw-r--r--src/core/hle/service/hid/controllers/types/mouse_types.h8
-rw-r--r--src/core/hle/service/hid/controllers/types/npad_types.h254
-rw-r--r--src/core/hle/service/hid/controllers/types/touch_types.h90
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h112
-rw-r--r--src/core/hle/service/hid/errors.h8
-rw-r--r--src/core/hle/service/hid/hid.cpp8
-rw-r--r--src/core/hle/service/hid/hid_server.cpp32
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp139
-rw-r--r--src/core/hle/service/hid/hid_system_server.h6
-rw-r--r--src/core/hle/service/hid/resource_manager.cpp160
-rw-r--r--src/core/hle/service/hid/resource_manager.h44
-rw-r--r--src/core/hle/service/hle_ipc.cpp15
-rw-r--r--src/core/hle/service/hle_ipc.h15
-rw-r--r--src/core/hle/service/jit/jit.cpp6
-rw-r--r--src/core/hle/service/ldr/ldr.cpp634
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp1
-rw-r--r--src/core/hle/service/ro/ro.cpp709
-rw-r--r--src/core/hle/service/ro/ro.h14
-rw-r--r--src/core/hle/service/ro/ro_nro_utils.cpp185
-rw-r--r--src/core/hle/service/ro/ro_nro_utils.h26
-rw-r--r--src/core/hle/service/ro/ro_results.h24
-rw-r--r--src/core/hle/service/ro/ro_types.h181
-rw-r--r--src/core/hle/service/server_manager.cpp32
-rw-r--r--src/core/hle/service/server_manager.h14
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/sm/sm.cpp33
-rw-r--r--src/core/hle/service/sm/sm.h14
-rw-r--r--src/core/hle/service/ssl/ssl.cpp6
-rw-r--r--src/core/memory.cpp10
-rw-r--r--src/core/memory.h2
-rw-r--r--src/core/memory/cheat_engine.cpp2
-rw-r--r--src/core/reporter.cpp32
-rw-r--r--src/tests/video_core/memory_tracker.cpp6
-rw-r--r--src/video_core/buffer_cache/word_manager.h2
-rw-r--r--src/video_core/host1x/ffmpeg/ffmpeg.cpp7
-rw-r--r--src/video_core/rasterizer_accelerated.cpp99
-rw-r--r--src/video_core/rasterizer_accelerated.h29
-rw-r--r--src/video_core/rasterizer_interface.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp9
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h1
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp32
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.h7
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.cpp13
-rw-r--r--src/video_core/renderer_vulkan/vk_present_manager.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp4
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp15
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.h21
-rw-r--r--src/video_core/shader_cache.cpp4
-rw-r--r--src/video_core/texture_cache/texture_cache.h45
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h3
-rw-r--r--src/yuzu/applets/qt_profile_select.cpp14
-rw-r--r--src/yuzu/applets/qt_profile_select.h15
-rw-r--r--src/yuzu/configuration/configure_debug.ui2
-rw-r--r--src/yuzu/configuration/configure_profile_manager.cpp36
-rw-r--r--src/yuzu/configuration/configure_profile_manager.h5
-rw-r--r--src/yuzu/debugger/wait_tree.cpp8
-rw-r--r--src/yuzu/main.cpp19
-rw-r--r--src/yuzu/multiplayer/lobby.cpp11
-rw-r--r--src/yuzu/multiplayer/lobby.h5
-rw-r--r--src/yuzu/play_time_manager.cpp21
-rw-r--r--src/yuzu/play_time_manager.h12
173 files changed, 7437 insertions, 5343 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt
index dec2b7cf1..9fab88248 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AddGameFolderDialogFragment.kt
@@ -14,8 +14,10 @@ import org.yuzu.yuzu_emu.R
14import org.yuzu.yuzu_emu.databinding.DialogAddFolderBinding 14import org.yuzu.yuzu_emu.databinding.DialogAddFolderBinding
15import org.yuzu.yuzu_emu.model.GameDir 15import org.yuzu.yuzu_emu.model.GameDir
16import org.yuzu.yuzu_emu.model.GamesViewModel 16import org.yuzu.yuzu_emu.model.GamesViewModel
17import org.yuzu.yuzu_emu.model.HomeViewModel
17 18
18class AddGameFolderDialogFragment : DialogFragment() { 19class AddGameFolderDialogFragment : DialogFragment() {
20 private val homeViewModel: HomeViewModel by activityViewModels()
19 private val gamesViewModel: GamesViewModel by activityViewModels() 21 private val gamesViewModel: GamesViewModel by activityViewModels()
20 22
21 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 23 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
@@ -30,6 +32,7 @@ class AddGameFolderDialogFragment : DialogFragment() {
30 .setTitle(R.string.add_game_folder) 32 .setTitle(R.string.add_game_folder)
31 .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> 33 .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
32 val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked) 34 val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked)
35 homeViewModel.setGamesDirSelected(true)
33 gamesViewModel.addFolder(newGameDir) 36 gamesViewModel.addFolder(newGameDir)
34 } 37 }
35 .setNegativeButton(android.R.string.cancel, null) 38 .setNegativeButton(android.R.string.cancel, null)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
index c4277735d..eb5edaa10 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt
@@ -4,6 +4,7 @@
4package org.yuzu.yuzu_emu.fragments 4package org.yuzu.yuzu_emu.fragments
5 5
6import android.Manifest 6import android.Manifest
7import android.annotation.SuppressLint
7import android.content.Intent 8import android.content.Intent
8import android.os.Build 9import android.os.Build
9import android.os.Bundle 10import android.os.Bundle
@@ -75,6 +76,8 @@ class SetupFragment : Fragment() {
75 return binding.root 76 return binding.root
76 } 77 }
77 78
79 // This is using the correct scope, lint is just acting up
80 @SuppressLint("UnsafeRepeatOnLifecycleDetector")
78 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 81 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
79 mainActivity = requireActivity() as MainActivity 82 mainActivity = requireActivity() as MainActivity
80 83
@@ -206,12 +209,24 @@ class SetupFragment : Fragment() {
206 ) 209 )
207 } 210 }
208 211
209 viewLifecycleOwner.lifecycleScope.launch { 212 viewLifecycleOwner.lifecycleScope.apply {
210 repeatOnLifecycle(Lifecycle.State.CREATED) { 213 launch {
211 homeViewModel.shouldPageForward.collect { 214 repeatOnLifecycle(Lifecycle.State.CREATED) {
212 if (it) { 215 homeViewModel.shouldPageForward.collect {
213 pageForward() 216 if (it) {
214 homeViewModel.setShouldPageForward(false) 217 pageForward()
218 homeViewModel.setShouldPageForward(false)
219 }
220 }
221 }
222 }
223 launch {
224 repeatOnLifecycle(Lifecycle.State.CREATED) {
225 homeViewModel.gamesDirSelected.collect {
226 if (it) {
227 gamesDirCallback.onStepCompleted()
228 homeViewModel.setGamesDirSelected(false)
229 }
215 } 230 }
216 } 231 }
217 } 232 }
@@ -339,7 +354,6 @@ class SetupFragment : Fragment() {
339 registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result -> 354 registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
340 if (result != null) { 355 if (result != null) {
341 mainActivity.processGamesDir(result) 356 mainActivity.processGamesDir(result)
342 gamesDirCallback.onStepCompleted()
343 } 357 }
344 } 358 }
345 359
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
index 752d98c10..fd925235b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
@@ -133,7 +133,7 @@ class GamesViewModel : ViewModel() {
133 viewModelScope.launch { 133 viewModelScope.launch {
134 withContext(Dispatchers.IO) { 134 withContext(Dispatchers.IO) {
135 NativeConfig.addGameDir(gameDir) 135 NativeConfig.addGameDir(gameDir)
136 getGameDirs() 136 getGameDirs(true)
137 } 137 }
138 } 138 }
139 139
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt
index 251b5a667..07e65b028 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt
@@ -6,6 +6,7 @@ package org.yuzu.yuzu_emu.model
6import androidx.lifecycle.ViewModel 6import androidx.lifecycle.ViewModel
7import kotlinx.coroutines.flow.MutableStateFlow 7import kotlinx.coroutines.flow.MutableStateFlow
8import kotlinx.coroutines.flow.StateFlow 8import kotlinx.coroutines.flow.StateFlow
9import kotlinx.coroutines.flow.asStateFlow
9 10
10class HomeViewModel : ViewModel() { 11class HomeViewModel : ViewModel() {
11 val navigationVisible: StateFlow<Pair<Boolean, Boolean>> get() = _navigationVisible 12 val navigationVisible: StateFlow<Pair<Boolean, Boolean>> get() = _navigationVisible
@@ -17,6 +18,9 @@ class HomeViewModel : ViewModel() {
17 val shouldPageForward: StateFlow<Boolean> get() = _shouldPageForward 18 val shouldPageForward: StateFlow<Boolean> get() = _shouldPageForward
18 private val _shouldPageForward = MutableStateFlow(false) 19 private val _shouldPageForward = MutableStateFlow(false)
19 20
21 private val _gamesDirSelected = MutableStateFlow(false)
22 val gamesDirSelected get() = _gamesDirSelected.asStateFlow()
23
20 var navigatedToSetup = false 24 var navigatedToSetup = false
21 25
22 fun setNavigationVisibility(visible: Boolean, animated: Boolean) { 26 fun setNavigationVisibility(visible: Boolean, animated: Boolean) {
@@ -36,4 +40,8 @@ class HomeViewModel : ViewModel() {
36 fun setShouldPageForward(pageForward: Boolean) { 40 fun setShouldPageForward(pageForward: Boolean) {
37 _shouldPageForward.value = pageForward 41 _shouldPageForward.value = pageForward
38 } 42 }
43
44 fun setGamesDirSelected(selected: Boolean) {
45 _gamesDirSelected.value = selected
46 }
39} 47}
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 3d795b57f..e5d3158c8 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -291,9 +291,6 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
291 // Initialize filesystem. 291 // Initialize filesystem.
292 ConfigureFilesystemProvider(filepath); 292 ConfigureFilesystemProvider(filepath);
293 293
294 // Initialize account manager
295 m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
296
297 // Load the ROM. 294 // Load the ROM.
298 m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath); 295 m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath);
299 if (m_load_result != Core::SystemResultStatus::Success) { 296 if (m_load_result != Core::SystemResultStatus::Success) {
@@ -736,8 +733,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
736 auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory( 733 auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory(
737 Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); 734 Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read);
738 735
739 Service::Account::ProfileManager manager; 736 const auto user_id = EmulationSession::GetInstance().System().GetProfileManager().GetUser(
740 const auto user_id = manager.GetUser(static_cast<std::size_t>(0)); 737 static_cast<std::size_t>(0));
741 ASSERT(user_id); 738 ASSERT(user_id);
742 739
743 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 740 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h
index 78ef96802..f1457bd1f 100644
--- a/src/android/app/src/main/jni/native.h
+++ b/src/android/app/src/main/jni/native.h
@@ -73,7 +73,6 @@ private:
73 std::atomic<bool> m_is_running = false; 73 std::atomic<bool> m_is_running = false;
74 std::atomic<bool> m_is_paused = false; 74 std::atomic<bool> m_is_paused = false;
75 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; 75 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
76 std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
77 std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; 76 std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
78 77
79 // GPU driver parameters 78 // GPU driver parameters
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 4bfc64f2d..e540375b8 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -11,10 +11,6 @@
11 11
12#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv 12#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
13 13
14#ifdef ANDROID
15#include <android/sharedmem.h>
16#endif
17
18#ifndef _GNU_SOURCE 14#ifndef _GNU_SOURCE
19#define _GNU_SOURCE 15#define _GNU_SOURCE
20#endif 16#endif
@@ -193,6 +189,11 @@ public:
193 } 189 }
194 } 190 }
195 191
192 bool ClearBackingRegion(size_t physical_offset, size_t length) {
193 // TODO: This does not seem to be possible on Windows.
194 return false;
195 }
196
196 void EnableDirectMappedAddress() { 197 void EnableDirectMappedAddress() {
197 // TODO 198 // TODO
198 UNREACHABLE(); 199 UNREACHABLE();
@@ -442,9 +443,7 @@ public:
442 } 443 }
443 444
444 // Backing memory initialization 445 // Backing memory initialization
445#ifdef ANDROID 446#if defined(__FreeBSD__) && __FreeBSD__ < 13
446 fd = ASharedMemory_create("HostMemory", backing_size);
447#elif defined(__FreeBSD__) && __FreeBSD__ < 13
448 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 447 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30
449 fd = shm_open(SHM_ANON, O_RDWR, 0600); 448 fd = shm_open(SHM_ANON, O_RDWR, 0600);
450#else 449#else
@@ -455,7 +454,6 @@ public:
455 throw std::bad_alloc{}; 454 throw std::bad_alloc{};
456 } 455 }
457 456
458#ifndef ANDROID
459 // Defined to extend the file with zeros 457 // Defined to extend the file with zeros
460 int ret = ftruncate(fd, backing_size); 458 int ret = ftruncate(fd, backing_size);
461 if (ret != 0) { 459 if (ret != 0) {
@@ -463,7 +461,6 @@ public:
463 strerror(errno)); 461 strerror(errno));
464 throw std::bad_alloc{}; 462 throw std::bad_alloc{};
465 } 463 }
466#endif
467 464
468 backing_base = static_cast<u8*>( 465 backing_base = static_cast<u8*>(
469 mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); 466 mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
@@ -552,6 +549,19 @@ public:
552 ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno)); 549 ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno));
553 } 550 }
554 551
552 bool ClearBackingRegion(size_t physical_offset, size_t length) {
553#ifdef __linux__
554 // Set MADV_REMOVE on backing map to destroy it instantly.
555 // This also deletes the area from the backing file.
556 int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
557 ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
558
559 return true;
560#else
561 return false;
562#endif
563 }
564
555 void EnableDirectMappedAddress() { 565 void EnableDirectMappedAddress() {
556 virtual_base = nullptr; 566 virtual_base = nullptr;
557 } 567 }
@@ -623,6 +633,10 @@ public:
623 633
624 void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {} 634 void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {}
625 635
636 bool ClearBackingRegion(size_t physical_offset, size_t length) {
637 return false;
638 }
639
626 void EnableDirectMappedAddress() {} 640 void EnableDirectMappedAddress() {}
627 641
628 u8* backing_base{nullptr}; 642 u8* backing_base{nullptr};
@@ -698,6 +712,12 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool w
698 impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); 712 impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute);
699} 713}
700 714
715void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) {
716 if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) {
717 std::memset(backing_base + physical_offset, fill_value, length);
718 }
719}
720
701void HostMemory::EnableDirectMappedAddress() { 721void HostMemory::EnableDirectMappedAddress() {
702 if (impl) { 722 if (impl) {
703 impl->EnableDirectMappedAddress(); 723 impl->EnableDirectMappedAddress();
diff --git a/src/common/host_memory.h b/src/common/host_memory.h
index cebfacab2..747c5850c 100644
--- a/src/common/host_memory.h
+++ b/src/common/host_memory.h
@@ -48,6 +48,8 @@ public:
48 48
49 void EnableDirectMappedAddress(); 49 void EnableDirectMappedAddress();
50 50
51 void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value);
52
51 [[nodiscard]] u8* BackingBasePointer() noexcept { 53 [[nodiscard]] u8* BackingBasePointer() noexcept {
52 return backing_base; 54 return backing_base;
53 } 55 }
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 4666bd0a0..88f509ba7 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -160,12 +160,16 @@ static bool is_nce_enabled = false;
160 160
161void SetNceEnabled(bool is_39bit) { 161void SetNceEnabled(bool is_39bit) {
162 const bool is_nce_selected = values.cpu_backend.GetValue() == CpuBackend::Nce; 162 const bool is_nce_selected = values.cpu_backend.GetValue() == CpuBackend::Nce;
163 is_nce_enabled = IsFastmemEnabled() && is_nce_selected && is_39bit; 163 if (is_nce_selected && !IsFastmemEnabled()) {
164 if (is_nce_selected && !is_nce_enabled) { 164 LOG_WARNING(Common, "Fastmem is required to natively execute code in a performant manner, "
165 "falling back to Dynarmic");
166 }
167 if (is_nce_selected && !is_39bit) {
165 LOG_WARNING( 168 LOG_WARNING(
166 Common, 169 Common,
167 "Program does not utilize 39-bit address space, unable to natively execute code"); 170 "Program does not utilize 39-bit address space, unable to natively execute code");
168 } 171 }
172 is_nce_enabled = IsFastmemEnabled() && is_nce_selected && is_39bit;
169} 173}
170 174
171bool IsNceEnabled() { 175bool IsNceEnabled() {
diff --git a/src/common/settings.h b/src/common/settings.h
index 98341ad96..7dc18fffe 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -180,14 +180,20 @@ struct Values {
180 &use_speed_limit}; 180 &use_speed_limit};
181 181
182 // Cpu 182 // Cpu
183 SwitchableSetting<CpuBackend, true> cpu_backend{ 183 SwitchableSetting<CpuBackend, true> cpu_backend{linkage,
184 linkage, CpuBackend::Dynarmic, CpuBackend::Dynarmic,
185#ifdef HAS_NCE 184#ifdef HAS_NCE
186 CpuBackend::Nce, 185 CpuBackend::Nce,
187#else 186#else
188 CpuBackend::Dynarmic, 187 CpuBackend::Dynarmic,
189#endif 188#endif
190 "cpu_backend", Category::Cpu}; 189 CpuBackend::Dynarmic,
190#ifdef HAS_NCE
191 CpuBackend::Nce,
192#else
193 CpuBackend::Dynarmic,
194#endif
195 "cpu_backend",
196 Category::Cpu};
191 SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto, 197 SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
192 CpuAccuracy::Auto, CpuAccuracy::Paranoid, 198 CpuAccuracy::Auto, CpuAccuracy::Paranoid,
193 "cpu_accuracy", Category::Cpu}; 199 "cpu_accuracy", Category::Cpu};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 85583941c..dced37079 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -4,6 +4,8 @@
4add_library(core STATIC 4add_library(core STATIC
5 arm/arm_interface.h 5 arm/arm_interface.h
6 arm/arm_interface.cpp 6 arm/arm_interface.cpp
7 arm/debug.cpp
8 arm/debug.h
7 arm/exclusive_monitor.cpp 9 arm/exclusive_monitor.cpp
8 arm/exclusive_monitor.h 10 arm/exclusive_monitor.h
9 arm/symbols.cpp 11 arm/symbols.cpp
@@ -249,10 +251,16 @@ add_library(core STATIC
249 hle/kernel/k_hardware_timer.h 251 hle/kernel/k_hardware_timer.h
250 hle/kernel/k_interrupt_manager.cpp 252 hle/kernel/k_interrupt_manager.cpp
251 hle/kernel/k_interrupt_manager.h 253 hle/kernel/k_interrupt_manager.h
254 hle/kernel/k_light_client_session.cpp
255 hle/kernel/k_light_client_session.h
252 hle/kernel/k_light_condition_variable.cpp 256 hle/kernel/k_light_condition_variable.cpp
253 hle/kernel/k_light_condition_variable.h 257 hle/kernel/k_light_condition_variable.h
254 hle/kernel/k_light_lock.cpp 258 hle/kernel/k_light_lock.cpp
255 hle/kernel/k_light_lock.h 259 hle/kernel/k_light_lock.h
260 hle/kernel/k_light_server_session.cpp
261 hle/kernel/k_light_server_session.h
262 hle/kernel/k_light_session.cpp
263 hle/kernel/k_light_session.h
256 hle/kernel/k_memory_block.h 264 hle/kernel/k_memory_block.h
257 hle/kernel/k_memory_block_manager.cpp 265 hle/kernel/k_memory_block_manager.cpp
258 hle/kernel/k_memory_block_manager.h 266 hle/kernel/k_memory_block_manager.h
@@ -541,6 +549,13 @@ add_library(core STATIC
541 hle/service/hid/xcd.cpp 549 hle/service/hid/xcd.cpp
542 hle/service/hid/xcd.h 550 hle/service/hid/xcd.h
543 hle/service/hid/errors.h 551 hle/service/hid/errors.h
552 hle/service/hid/controllers/types/debug_pad_types.h
553 hle/service/hid/controllers/types/keyboard_types.h
554 hle/service/hid/controllers/types/mouse_types.h
555 hle/service/hid/controllers/types/npad_types.h
556 hle/service/hid/controllers/types/touch_types.h
557 hle/service/hid/controllers/applet_resource.cpp
558 hle/service/hid/controllers/applet_resource.h
544 hle/service/hid/controllers/console_six_axis.cpp 559 hle/service/hid/controllers/console_six_axis.cpp
545 hle/service/hid/controllers/console_six_axis.h 560 hle/service/hid/controllers/console_six_axis.h
546 hle/service/hid/controllers/controller_base.cpp 561 hle/service/hid/controllers/controller_base.cpp
@@ -559,14 +574,15 @@ add_library(core STATIC
559 hle/service/hid/controllers/palma.h 574 hle/service/hid/controllers/palma.h
560 hle/service/hid/controllers/seven_six_axis.cpp 575 hle/service/hid/controllers/seven_six_axis.cpp
561 hle/service/hid/controllers/seven_six_axis.h 576 hle/service/hid/controllers/seven_six_axis.h
577 hle/service/hid/controllers/shared_memory_format.h
578 hle/service/hid/controllers/shared_memory_holder.cpp
579 hle/service/hid/controllers/shared_memory_holder.h
562 hle/service/hid/controllers/six_axis.cpp 580 hle/service/hid/controllers/six_axis.cpp
563 hle/service/hid/controllers/six_axis.h 581 hle/service/hid/controllers/six_axis.h
564 hle/service/hid/controllers/stubbed.cpp 582 hle/service/hid/controllers/stubbed.cpp
565 hle/service/hid/controllers/stubbed.h 583 hle/service/hid/controllers/stubbed.h
566 hle/service/hid/controllers/touchscreen.cpp 584 hle/service/hid/controllers/touchscreen.cpp
567 hle/service/hid/controllers/touchscreen.h 585 hle/service/hid/controllers/touchscreen.h
568 hle/service/hid/controllers/xpad.cpp
569 hle/service/hid/controllers/xpad.h
570 hle/service/hid/hidbus/hidbus_base.cpp 586 hle/service/hid/hidbus/hidbus_base.cpp
571 hle/service/hid/hidbus/hidbus_base.h 587 hle/service/hid/hidbus/hidbus_base.h
572 hle/service/hid/hidbus/ringcon.cpp 588 hle/service/hid/hidbus/ringcon.cpp
@@ -762,6 +778,12 @@ add_library(core STATIC
762 hle/service/kernel_helpers.h 778 hle/service/kernel_helpers.h
763 hle/service/mutex.cpp 779 hle/service/mutex.cpp
764 hle/service/mutex.h 780 hle/service/mutex.h
781 hle/service/ro/ro_nro_utils.cpp
782 hle/service/ro/ro_nro_utils.h
783 hle/service/ro/ro_results.h
784 hle/service/ro/ro_types.h
785 hle/service/ro/ro.cpp
786 hle/service/ro/ro.h
765 hle/service/server_manager.cpp 787 hle/service/server_manager.cpp
766 hle/service/server_manager.h 788 hle/service/server_manager.h
767 hle/service/service.cpp 789 hle/service/service.cpp
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index d231bf89c..698c9c8ad 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -1,231 +1,32 @@
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 <map>
5#include <optional>
6
7#include "common/bit_field.h"
8#include "common/common_types.h"
9#include "common/demangle.h"
10#include "common/logging/log.h" 4#include "common/logging/log.h"
11#include "core/arm/arm_interface.h" 5#include "core/arm/arm_interface.h"
12#include "core/arm/symbols.h" 6#include "core/arm/debug.h"
13#include "core/core.h" 7#include "core/core.h"
14#include "core/debugger/debugger.h"
15#include "core/hle/kernel/k_process.h" 8#include "core/hle/kernel/k_process.h"
16#include "core/hle/kernel/k_thread.h"
17#include "core/hle/kernel/svc.h"
18#include "core/loader/loader.h"
19#include "core/memory.h"
20 9
21namespace Core { 10namespace Core {
22 11
23constexpr u64 SEGMENT_BASE = 0x7100000000ull; 12void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const {
24 13 Kernel::Svc::ThreadContext ctx;
25std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( 14 this->GetContext(ctx);
26 Core::System& system, const ARM_Interface::ThreadContext32& ctx) {
27 std::vector<BacktraceEntry> out;
28 auto& memory = system.ApplicationMemory();
29
30 const auto& reg = ctx.cpu_registers;
31 u32 pc = reg[15], lr = reg[14], fp = reg[11];
32 out.push_back({"", 0, pc, 0, ""});
33
34 // fp (= r11) points to the last frame record.
35 // Frame records are two words long:
36 // fp+0 : pointer to previous frame record
37 // fp+4 : value of lr for frame
38 for (size_t i = 0; i < 256; i++) {
39 out.push_back({"", 0, lr, 0, ""});
40 if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
41 break;
42 }
43 lr = memory.Read32(fp + 4);
44 fp = memory.Read32(fp);
45 }
46
47 SymbolicateBacktrace(system, out);
48
49 return out;
50}
51
52std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext(
53 Core::System& system, const ARM_Interface::ThreadContext64& ctx) {
54 std::vector<BacktraceEntry> out;
55 auto& memory = system.ApplicationMemory();
56
57 const auto& reg = ctx.cpu_registers;
58 u64 pc = ctx.pc, lr = reg[30], fp = reg[29];
59
60 out.push_back({"", 0, pc, 0, ""});
61
62 // fp (= x29) points to the previous frame record.
63 // Frame records are two words long:
64 // fp+0 : pointer to previous frame record
65 // fp+8 : value of lr for frame
66 for (size_t i = 0; i < 256; i++) {
67 out.push_back({"", 0, lr, 0, ""});
68 if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
69 break;
70 }
71 lr = memory.Read64(fp + 8);
72 fp = memory.Read64(fp);
73 }
74
75 SymbolicateBacktrace(system, out);
76
77 return out;
78}
79
80void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out) {
81 std::map<VAddr, std::string> modules;
82 auto& loader{system.GetAppLoader()};
83 if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) {
84 return;
85 }
86
87 std::map<std::string, Symbols::Symbols> symbols;
88 for (const auto& module : modules) {
89 symbols.insert_or_assign(module.second,
90 Symbols::GetSymbols(module.first, system.ApplicationMemory(),
91 system.ApplicationProcess()->Is64Bit()));
92 }
93
94 for (auto& entry : out) {
95 VAddr base = 0;
96 for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) {
97 const auto& module{*iter};
98 if (entry.original_address >= module.first) {
99 entry.module = module.second;
100 base = module.first;
101 break;
102 }
103 }
104
105 entry.offset = entry.original_address - base;
106 entry.address = SEGMENT_BASE + entry.offset;
107
108 if (entry.module.empty()) {
109 entry.module = "unknown";
110 }
111
112 const auto symbol_set = symbols.find(entry.module);
113 if (symbol_set != symbols.end()) {
114 const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
115 if (symbol) {
116 entry.name = Common::DemangleSymbol(*symbol);
117 }
118 }
119 }
120}
121
122std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
123 if (GetArchitecture() == Architecture::Aarch64) {
124 ThreadContext64 ctx;
125 SaveContext(ctx);
126 return GetBacktraceFromContext(system, ctx);
127 } else {
128 ThreadContext32 ctx;
129 SaveContext(ctx);
130 return GetBacktraceFromContext(system, ctx);
131 }
132}
133 15
134void ARM_Interface::LogBacktrace() const { 16 LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", ctx.sp, ctx.pc);
135 const VAddr sp = GetSP();
136 const VAddr pc = GetPC();
137 LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc);
138 LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", 17 LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address",
139 "Offset", "Symbol"); 18 "Offset", "Symbol");
140 LOG_ERROR(Core_ARM, ""); 19 LOG_ERROR(Core_ARM, "");
141 const auto backtrace = GetBacktrace(); 20 const auto backtrace = GetBacktraceFromContext(process, ctx);
142 for (const auto& entry : backtrace) { 21 for (const auto& entry : backtrace) {
143 LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, 22 LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
144 entry.original_address, entry.offset, entry.name); 23 entry.original_address, entry.offset, entry.name);
145 } 24 }
146} 25}
147 26
148void ARM_Interface::Run() { 27const Kernel::DebugWatchpoint* ArmInterface::MatchingWatchpoint(
149 using Kernel::StepState;
150 using Kernel::SuspendType;
151
152 while (true) {
153 Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())};
154 HaltReason hr{};
155
156 // If the thread is scheduled for termination, exit the thread.
157 if (current_thread->HasDpc()) {
158 if (current_thread->IsTerminationRequested()) {
159 current_thread->Exit();
160 UNREACHABLE();
161 }
162 }
163
164 // Notify the debugger and go to sleep if a step was performed
165 // and this thread has been scheduled again.
166 if (current_thread->GetStepState() == StepState::StepPerformed) {
167 system.GetDebugger().NotifyThreadStopped(current_thread);
168 current_thread->RequestSuspend(SuspendType::Debug);
169 break;
170 }
171
172 // Otherwise, run the thread.
173 system.EnterCPUProfile();
174 if (current_thread->GetStepState() == StepState::StepPending) {
175 hr = StepJit();
176
177 if (True(hr & HaltReason::StepThread)) {
178 current_thread->SetStepState(StepState::StepPerformed);
179 }
180 } else {
181 hr = RunJit();
182 }
183 system.ExitCPUProfile();
184
185 // Notify the debugger and go to sleep if a breakpoint was hit,
186 // or if the thread is unable to continue for any reason.
187 if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) {
188 if (!True(hr & HaltReason::PrefetchAbort)) {
189 RewindBreakpointInstruction();
190 }
191 if (system.DebuggerEnabled()) {
192 system.GetDebugger().NotifyThreadStopped(current_thread);
193 } else {
194 LogBacktrace();
195 }
196 current_thread->RequestSuspend(SuspendType::Debug);
197 break;
198 }
199
200 // Notify the debugger and go to sleep if a watchpoint was hit.
201 if (True(hr & HaltReason::DataAbort)) {
202 if (system.DebuggerEnabled()) {
203 system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint());
204 } else {
205 LogBacktrace();
206 }
207 current_thread->RequestSuspend(SuspendType::Debug);
208 break;
209 }
210
211 // Handle syscalls and scheduling (this may change the current thread/core)
212 if (True(hr & HaltReason::SupervisorCall)) {
213 Kernel::Svc::Call(system, GetSvcNumber());
214 break;
215 }
216 if (True(hr & HaltReason::BreakLoop) || !uses_wall_clock) {
217 break;
218 }
219 }
220}
221
222void ARM_Interface::LoadWatchpointArray(const WatchpointArray* wp) {
223 watchpoints = wp;
224}
225
226const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint(
227 u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const { 28 u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const {
228 if (!watchpoints) { 29 if (!m_watchpoints) {
229 return nullptr; 30 return nullptr;
230 } 31 }
231 32
@@ -233,7 +34,7 @@ const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint(
233 const u64 end_address{addr + size}; 34 const u64 end_address{addr + size};
234 35
235 for (size_t i = 0; i < Core::Hardware::NUM_WATCHPOINTS; i++) { 36 for (size_t i = 0; i < Core::Hardware::NUM_WATCHPOINTS; i++) {
236 const auto& watch{(*watchpoints)[i]}; 37 const auto& watch{(*m_watchpoints)[i]};
237 38
238 if (end_address <= GetInteger(watch.start_address)) { 39 if (end_address <= GetInteger(watch.start_address)) {
239 continue; 40 continue;
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index a9d9ac09d..806c7c9e9 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -12,20 +12,20 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/hardware_properties.h" 13#include "core/hardware_properties.h"
14 14
15#include "core/hle/kernel/svc_types.h"
16
15namespace Common { 17namespace Common {
16struct PageTable; 18struct PageTable;
17} 19}
18 20
19namespace Kernel { 21namespace Kernel {
20enum class VMAPermission : u8;
21enum class DebugWatchpointType : u8; 22enum class DebugWatchpointType : u8;
22struct DebugWatchpoint; 23struct DebugWatchpoint;
24class KThread;
25class KProcess;
23} // namespace Kernel 26} // namespace Kernel
24 27
25namespace Core { 28namespace Core {
26class System;
27class CPUInterruptHandler;
28
29using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>; 29using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
30 30
31// NOTE: these values match the HaltReason enum in Dynarmic 31// NOTE: these values match the HaltReason enum in Dynarmic
@@ -40,197 +40,74 @@ enum class HaltReason : u64 {
40DECLARE_ENUM_FLAG_OPERATORS(HaltReason); 40DECLARE_ENUM_FLAG_OPERATORS(HaltReason);
41 41
42enum class Architecture { 42enum class Architecture {
43 Aarch32, 43 AArch64,
44 Aarch64, 44 AArch32,
45}; 45};
46 46
47/// Generic ARMv8 CPU interface 47/// Generic ARMv8 CPU interface
48class ARM_Interface { 48class ArmInterface {
49public: 49public:
50 YUZU_NON_COPYABLE(ARM_Interface); 50 YUZU_NON_COPYABLE(ArmInterface);
51 YUZU_NON_MOVEABLE(ARM_Interface); 51 YUZU_NON_MOVEABLE(ArmInterface);
52 52
53 explicit ARM_Interface(System& system_, bool uses_wall_clock_) 53 explicit ArmInterface(bool uses_wall_clock) : m_uses_wall_clock{uses_wall_clock} {}
54 : system{system_}, uses_wall_clock{uses_wall_clock_} {} 54 virtual ~ArmInterface() = default;
55 virtual ~ARM_Interface() = default; 55
56 56 // Perform any backend-specific initialization.
57 struct ThreadContext32 {
58 std::array<u32, 16> cpu_registers{};
59 std::array<u32, 64> extension_registers{};
60 u32 cpsr{};
61 u32 fpscr{};
62 u32 fpexc{};
63 u32 tpidr{};
64 };
65 // Internally within the kernel, it expects the AArch32 version of the
66 // thread context to be 344 bytes in size.
67 static_assert(sizeof(ThreadContext32) == 0x150);
68
69 struct ThreadContext64 {
70 std::array<u64, 31> cpu_registers{};
71 u64 sp{};
72 u64 pc{};
73 u32 pstate{};
74 std::array<u8, 4> padding{};
75 std::array<u128, 32> vector_registers{};
76 u32 fpcr{};
77 u32 fpsr{};
78 u64 tpidr{};
79 };
80 // Internally within the kernel, it expects the AArch64 version of the
81 // thread context to be 800 bytes in size.
82 static_assert(sizeof(ThreadContext64) == 0x320);
83
84 /// Perform any backend-specific initialization.
85 virtual void Initialize() {} 57 virtual void Initialize() {}
86 58
87 /// Runs the CPU until an event happens 59 // Runs the CPU until an event happens.
88 void Run(); 60 virtual HaltReason RunThread(Kernel::KThread* thread) = 0;
89 61
90 /// Clear all instruction cache 62 // Runs the CPU for one instruction or until an event happens.
63 virtual HaltReason StepThread(Kernel::KThread* thread) = 0;
64
65 // Admits a backend-specific mechanism to lock the thread context.
66 virtual void LockThread(Kernel::KThread* thread) {}
67 virtual void UnlockThread(Kernel::KThread* thread) {}
68
69 // Clear the entire instruction cache for this CPU.
91 virtual void ClearInstructionCache() = 0; 70 virtual void ClearInstructionCache() = 0;
92 71
93 /** 72 // Clear a range of the instruction cache for this CPU.
94 * Clear instruction cache range
95 * @param addr Start address of the cache range to clear
96 * @param size Size of the cache range to clear, starting at addr
97 */
98 virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0; 73 virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0;
99 74
100 /** 75 // Get the current architecture.
101 * Notifies CPU emulation that the current page table has changed. 76 // This returns AArch64 when PSTATE.nRW == 0 and AArch32 when PSTATE.nRW == 1.
102 * @param new_page_table The new page table.
103 * @param new_address_space_size_in_bits The new usable size of the address space in bits.
104 * This can be either 32, 36, or 39 on official software.
105 */
106 virtual void PageTableChanged(Common::PageTable& new_page_table,
107 std::size_t new_address_space_size_in_bits) = 0;
108
109 /**
110 * Set the Program Counter to an address
111 * @param addr Address to set PC to
112 */
113 virtual void SetPC(u64 addr) = 0;
114
115 /*
116 * Get the current Program Counter
117 * @return Returns current PC
118 */
119 virtual u64 GetPC() const = 0;
120
121 /**
122 * Get the current Stack Pointer
123 * @return Returns current SP
124 */
125 virtual u64 GetSP() const = 0;
126
127 /**
128 * Get an ARM register
129 * @param index Register index
130 * @return Returns the value in the register
131 */
132 virtual u64 GetReg(int index) const = 0;
133
134 /**
135 * Set an ARM register
136 * @param index Register index
137 * @param value Value to set register to
138 */
139 virtual void SetReg(int index, u64 value) = 0;
140
141 /**
142 * Gets the value of a specified vector register.
143 *
144 * @param index The index of the vector register.
145 * @return the value within the vector register.
146 */
147 virtual u128 GetVectorReg(int index) const = 0;
148
149 /**
150 * Sets a given value into a vector register.
151 *
152 * @param index The index of the vector register.
153 * @param value The new value to place in the register.
154 */
155 virtual void SetVectorReg(int index, u128 value) = 0;
156
157 /**
158 * Get the current PSTATE register
159 * @return Returns the value of the PSTATE register
160 */
161 virtual u32 GetPSTATE() const = 0;
162
163 /**
164 * Set the current PSTATE register
165 * @param pstate Value to set PSTATE to
166 */
167 virtual void SetPSTATE(u32 pstate) = 0;
168
169 virtual u64 GetTlsAddress() const = 0;
170
171 virtual void SetTlsAddress(u64 address) = 0;
172
173 /**
174 * Gets the value within the TPIDR_EL0 (read/write software thread ID) register.
175 *
176 * @return the value within the register.
177 */
178 virtual u64 GetTPIDR_EL0() const = 0;
179
180 /**
181 * Sets a new value within the TPIDR_EL0 (read/write software thread ID) register.
182 *
183 * @param value The new value to place in the register.
184 */
185 virtual void SetTPIDR_EL0(u64 value) = 0;
186
187 virtual Architecture GetArchitecture() const = 0; 77 virtual Architecture GetArchitecture() const = 0;
188 virtual void SaveContext(ThreadContext32& ctx) const = 0;
189 virtual void SaveContext(ThreadContext64& ctx) const = 0;
190 virtual void LoadContext(const ThreadContext32& ctx) = 0;
191 virtual void LoadContext(const ThreadContext64& ctx) = 0;
192 void LoadWatchpointArray(const WatchpointArray* wp);
193 78
194 /// Clears the exclusive monitor's state. 79 // Context accessors.
195 virtual void ClearExclusiveState() = 0; 80 // These should not be called if the CPU is running.
81 virtual void GetContext(Kernel::Svc::ThreadContext& ctx) const = 0;
82 virtual void SetContext(const Kernel::Svc::ThreadContext& ctx) = 0;
83 virtual void SetTpidrroEl0(u64 value) = 0;
196 84
197 /// Signal an interrupt and ask the core to halt as soon as possible. 85 virtual void GetSvcArguments(std::span<uint64_t, 8> args) const = 0;
198 virtual void SignalInterrupt() = 0; 86 virtual void SetSvcArguments(std::span<const uint64_t, 8> args) = 0;
87 virtual u32 GetSvcNumber() const = 0;
199 88
200 /// Clear a previous interrupt. 89 void SetWatchpointArray(const WatchpointArray* watchpoints) {
201 virtual void ClearInterrupt() = 0; 90 m_watchpoints = watchpoints;
91 }
202 92
203 struct BacktraceEntry { 93 // Signal an interrupt for execution to halt as soon as possible.
204 std::string module; 94 // It is safe to call this if the CPU is not running.
205 u64 address; 95 virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
206 u64 original_address;
207 u64 offset;
208 std::string name;
209 };
210 96
211 static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, 97 // Stack trace generation.
212 const ThreadContext32& ctx); 98 void LogBacktrace(const Kernel::KProcess* process) const;
213 static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system,
214 const ThreadContext64& ctx);
215 99
216 std::vector<BacktraceEntry> GetBacktrace() const; 100 // Debug functionality.
217 void LogBacktrace() const; 101 virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
102 virtual void RewindBreakpointInstruction() = 0;
218 103
219protected: 104protected:
220 /// System context that this ARM interface is running under.
221 System& system;
222 const WatchpointArray* watchpoints;
223 bool uses_wall_clock;
224
225 static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out);
226 const Kernel::DebugWatchpoint* MatchingWatchpoint( 105 const Kernel::DebugWatchpoint* MatchingWatchpoint(
227 u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const; 106 u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const;
228 107
229 virtual HaltReason RunJit() = 0; 108protected:
230 virtual HaltReason StepJit() = 0; 109 const WatchpointArray* m_watchpoints{};
231 virtual u32 GetSvcNumber() const = 0; 110 bool m_uses_wall_clock{};
232 virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;
233 virtual void RewindBreakpointInstruction() = 0;
234}; 111};
235 112
236} // namespace Core 113} // namespace Core
diff --git a/src/core/arm/debug.cpp b/src/core/arm/debug.cpp
new file mode 100644
index 000000000..af1c34bc3
--- /dev/null
+++ b/src/core/arm/debug.cpp
@@ -0,0 +1,354 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/demangle.h"
5#include "core/arm/debug.h"
6#include "core/arm/symbols.h"
7#include "core/hle/kernel/k_process.h"
8#include "core/hle/kernel/k_thread.h"
9#include "core/memory.h"
10
11namespace Core {
12
13namespace {
14
15std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory,
16 const Kernel::KThread& thread) {
17 // Read thread type from TLS
18 const VAddr tls_thread_type{memory.Read64(thread.GetTlsAddress() + 0x1f8)};
19 const VAddr argument_thread_type{thread.GetArgument()};
20
21 if (argument_thread_type && tls_thread_type != argument_thread_type) {
22 // Probably not created by nnsdk, no name available.
23 return std::nullopt;
24 }
25
26 if (!tls_thread_type) {
27 return std::nullopt;
28 }
29
30 const u16 version{memory.Read16(tls_thread_type + 0x46)};
31 VAddr name_pointer{};
32 if (version == 1) {
33 name_pointer = memory.Read64(tls_thread_type + 0x1a0);
34 } else {
35 name_pointer = memory.Read64(tls_thread_type + 0x1a8);
36 }
37
38 if (!name_pointer) {
39 // No name provided.
40 return std::nullopt;
41 }
42
43 return memory.ReadCString(name_pointer, 256);
44}
45
46std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory,
47 const Kernel::KThread& thread) {
48 // Read thread type from TLS
49 const VAddr tls_thread_type{memory.Read32(thread.GetTlsAddress() + 0x1fc)};
50 const VAddr argument_thread_type{thread.GetArgument()};
51
52 if (argument_thread_type && tls_thread_type != argument_thread_type) {
53 // Probably not created by nnsdk, no name available.
54 return std::nullopt;
55 }
56
57 if (!tls_thread_type) {
58 return std::nullopt;
59 }
60
61 const u16 version{memory.Read16(tls_thread_type + 0x26)};
62 VAddr name_pointer{};
63 if (version == 1) {
64 name_pointer = memory.Read32(tls_thread_type + 0xe4);
65 } else {
66 name_pointer = memory.Read32(tls_thread_type + 0xe8);
67 }
68
69 if (!name_pointer) {
70 // No name provided.
71 return std::nullopt;
72 }
73
74 return memory.ReadCString(name_pointer, 256);
75}
76
77constexpr std::array<u64, 2> SegmentBases{
78 0x60000000ULL,
79 0x7100000000ULL,
80};
81
82void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
83 auto modules = FindModules(process);
84
85 const bool is_64 = process->Is64Bit();
86
87 std::map<std::string, Symbols::Symbols> symbols;
88 for (const auto& module : modules) {
89 symbols.insert_or_assign(module.second,
90 Symbols::GetSymbols(module.first, process->GetMemory(), is_64));
91 }
92
93 for (auto& entry : out) {
94 VAddr base = 0;
95 for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) {
96 const auto& module{*iter};
97 if (entry.original_address >= module.first) {
98 entry.module = module.second;
99 base = module.first;
100 break;
101 }
102 }
103
104 entry.offset = entry.original_address - base;
105 entry.address = SegmentBases[is_64] + entry.offset;
106
107 if (entry.module.empty()) {
108 entry.module = "unknown";
109 }
110
111 const auto symbol_set = symbols.find(entry.module);
112 if (symbol_set != symbols.end()) {
113 const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
114 if (symbol) {
115 entry.name = Common::DemangleSymbol(*symbol);
116 }
117 }
118 }
119}
120
121std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
122 const Kernel::Svc::ThreadContext& ctx) {
123 std::vector<BacktraceEntry> out;
124 auto& memory = process->GetMemory();
125 auto pc = ctx.pc, lr = ctx.lr, fp = ctx.fp;
126
127 out.push_back({"", 0, pc, 0, ""});
128
129 // fp (= x29) points to the previous frame record.
130 // Frame records are two words long:
131 // fp+0 : pointer to previous frame record
132 // fp+8 : value of lr for frame
133 for (size_t i = 0; i < 256; i++) {
134 out.push_back({"", 0, lr, 0, ""});
135 if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) {
136 break;
137 }
138 lr = memory.Read64(fp + 8);
139 fp = memory.Read64(fp);
140 }
141
142 SymbolicateBacktrace(process, out);
143
144 return out;
145}
146
147std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
148 const Kernel::Svc::ThreadContext& ctx) {
149 std::vector<BacktraceEntry> out;
150 auto& memory = process->GetMemory();
151 auto pc = ctx.pc, lr = ctx.lr, fp = ctx.fp;
152
153 out.push_back({"", 0, pc, 0, ""});
154
155 // fp (= r11) points to the last frame record.
156 // Frame records are two words long:
157 // fp+0 : pointer to previous frame record
158 // fp+4 : value of lr for frame
159 for (size_t i = 0; i < 256; i++) {
160 out.push_back({"", 0, lr, 0, ""});
161 if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) {
162 break;
163 }
164 lr = memory.Read32(fp + 4);
165 fp = memory.Read32(fp);
166 }
167
168 SymbolicateBacktrace(process, out);
169
170 return out;
171}
172
173} // namespace
174
175std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
176 const auto* process = thread->GetOwnerProcess();
177 if (process->Is64Bit()) {
178 return GetNameFromThreadType64(process->GetMemory(), *thread);
179 } else {
180 return GetNameFromThreadType32(process->GetMemory(), *thread);
181 }
182}
183
184std::string_view GetThreadWaitReason(const Kernel::KThread* thread) {
185 switch (thread->GetWaitReasonForDebugging()) {
186 case Kernel::ThreadWaitReasonForDebugging::Sleep:
187 return "Sleep";
188 case Kernel::ThreadWaitReasonForDebugging::IPC:
189 return "IPC";
190 case Kernel::ThreadWaitReasonForDebugging::Synchronization:
191 return "Synchronization";
192 case Kernel::ThreadWaitReasonForDebugging::ConditionVar:
193 return "ConditionVar";
194 case Kernel::ThreadWaitReasonForDebugging::Arbitration:
195 return "Arbitration";
196 case Kernel::ThreadWaitReasonForDebugging::Suspended:
197 return "Suspended";
198 default:
199 return "Unknown";
200 }
201}
202
203std::string GetThreadState(const Kernel::KThread* thread) {
204 switch (thread->GetState()) {
205 case Kernel::ThreadState::Initialized:
206 return "Initialized";
207 case Kernel::ThreadState::Waiting:
208 return fmt::format("Waiting ({})", GetThreadWaitReason(thread));
209 case Kernel::ThreadState::Runnable:
210 return "Runnable";
211 case Kernel::ThreadState::Terminated:
212 return "Terminated";
213 default:
214 return "Unknown";
215 }
216}
217
218Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process,
219 Kernel::KProcessAddress base) {
220 Kernel::KMemoryInfo mem_info;
221 Kernel::Svc::MemoryInfo svc_mem_info;
222 Kernel::Svc::PageInfo page_info;
223 VAddr cur_addr{GetInteger(base)};
224 auto& page_table = process->GetPageTable();
225
226 // Expect: r-x Code (.text)
227 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
228 svc_mem_info = mem_info.GetSvcMemoryInfo();
229 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
230 if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
231 svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
232 return cur_addr - 1;
233 }
234
235 // Expect: r-- Code (.rodata)
236 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
237 svc_mem_info = mem_info.GetSvcMemoryInfo();
238 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
239 if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
240 svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
241 return cur_addr - 1;
242 }
243
244 // Expect: rw- CodeData (.data)
245 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
246 svc_mem_info = mem_info.GetSvcMemoryInfo();
247 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
248 return cur_addr - 1;
249}
250
251Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
252 Loader::AppLoader::Modules modules;
253
254 auto& page_table = process->GetPageTable();
255 auto& memory = process->GetMemory();
256 VAddr cur_addr = 0;
257
258 // Look for executable sections in Code or AliasCode regions.
259 while (true) {
260 Kernel::KMemoryInfo mem_info{};
261 Kernel::Svc::PageInfo page_info{};
262 R_ASSERT(
263 page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
264 auto svc_mem_info = mem_info.GetSvcMemoryInfo();
265
266 if (svc_mem_info.permission == Kernel::Svc::MemoryPermission::ReadExecute &&
267 (svc_mem_info.state == Kernel::Svc::MemoryState::Code ||
268 svc_mem_info.state == Kernel::Svc::MemoryState::AliasCode)) {
269 // Try to read the module name from its path.
270 constexpr s32 PathLengthMax = 0x200;
271 struct {
272 u32 zero;
273 s32 path_length;
274 std::array<char, PathLengthMax> path;
275 } module_path;
276
277 if (memory.ReadBlock(svc_mem_info.base_address + svc_mem_info.size, &module_path,
278 sizeof(module_path))) {
279 if (module_path.zero == 0 && module_path.path_length > 0) {
280 // Truncate module name.
281 module_path.path[PathLengthMax - 1] = '\0';
282
283 // Ignore leading directories.
284 char* path_pointer = module_path.path.data();
285 char* path_end =
286 path_pointer + std::min(PathLengthMax, module_path.path_length);
287
288 for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) &&
289 module_path.path[i] != '\0';
290 i++) {
291 if (module_path.path[i] == '/' || module_path.path[i] == '\\') {
292 path_pointer = module_path.path.data() + i + 1;
293 }
294 }
295
296 // Insert output.
297 modules.emplace(svc_mem_info.base_address,
298 std::string_view(path_pointer, path_end));
299 }
300 }
301 }
302
303 // Check if we're done.
304 const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size;
305 if (next_address <= cur_addr) {
306 break;
307 }
308
309 cur_addr = next_address;
310 }
311
312 return modules;
313}
314
315Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) {
316 // Do we have any loaded executable sections?
317 auto modules = FindModules(process);
318
319 if (modules.size() >= 2) {
320 // If we have two or more, the first one is rtld and the second is main.
321 return std::next(modules.begin())->first;
322 } else if (!modules.empty()) {
323 // If we only have one, this is the main module.
324 return modules.begin()->first;
325 }
326
327 // As a last resort, use the start of the code region.
328 return GetInteger(process->GetPageTable().GetCodeRegionStart());
329}
330
331void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size) {
332 for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
333 auto* interface = process->GetArmInterface(i);
334 if (interface) {
335 interface->InvalidateCacheRange(address, size);
336 }
337 }
338}
339
340std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
341 const Kernel::Svc::ThreadContext& ctx) {
342 if (process->Is64Bit()) {
343 return GetAArch64Backtrace(process, ctx);
344 } else {
345 return GetAArch32Backtrace(process, ctx);
346 }
347}
348
349std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread) {
350 Kernel::Svc::ThreadContext ctx = thread->GetContext();
351 return GetBacktraceFromContext(thread->GetOwnerProcess(), ctx);
352}
353
354} // namespace Core
diff --git a/src/core/arm/debug.h b/src/core/arm/debug.h
new file mode 100644
index 000000000..c542633db
--- /dev/null
+++ b/src/core/arm/debug.h
@@ -0,0 +1,35 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <optional>
7
8#include "core/hle/kernel/k_thread.h"
9#include "core/loader/loader.h"
10
11namespace Core {
12
13std::optional<std::string> GetThreadName(const Kernel::KThread* thread);
14std::string_view GetThreadWaitReason(const Kernel::KThread* thread);
15std::string GetThreadState(const Kernel::KThread* thread);
16
17Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process);
18Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base);
19Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process);
20
21void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size);
22
23struct BacktraceEntry {
24 std::string module;
25 u64 address;
26 u64 original_address;
27 u64 offset;
28 std::string name;
29};
30
31std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process,
32 const Kernel::Svc::ThreadContext& ctx);
33std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread);
34
35} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 44a297cdc..f34865e26 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -1,25 +1,13 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 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 <cinttypes>
5#include <memory>
6#include <dynarmic/interface/A32/a32.h>
7#include <dynarmic/interface/A32/config.h>
8#include "common/assert.h"
9#include "common/literals.h"
10#include "common/logging/log.h"
11#include "common/page_table.h"
12#include "common/settings.h" 4#include "common/settings.h"
13#include "core/arm/dynarmic/arm_dynarmic.h" 5#include "core/arm/dynarmic/arm_dynarmic.h"
14#include "core/arm/dynarmic/arm_dynarmic_32.h" 6#include "core/arm/dynarmic/arm_dynarmic_32.h"
15#include "core/arm/dynarmic/dynarmic_cp15.h" 7#include "core/arm/dynarmic/dynarmic_cp15.h"
16#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" 8#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
17#include "core/core.h"
18#include "core/core_timing.h" 9#include "core/core_timing.h"
19#include "core/debugger/debugger.h"
20#include "core/hle/kernel/k_process.h" 10#include "core/hle/kernel/k_process.h"
21#include "core/hle/kernel/svc.h"
22#include "core/memory.h"
23 11
24namespace Core { 12namespace Core {
25 13
@@ -27,78 +15,78 @@ using namespace Common::Literals;
27 15
28class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { 16class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
29public: 17public:
30 explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) 18 explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process)
31 : parent{parent_}, memory(parent.system.ApplicationMemory()), 19 : m_parent{parent}, m_memory(process->GetMemory()),
32 debugger_enabled{parent.system.DebuggerEnabled()}, 20 m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
33 check_memory_access{debugger_enabled || 21 m_check_memory_access{m_debugger_enabled ||
34 !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} 22 !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
35 23
36 u8 MemoryRead8(u32 vaddr) override { 24 u8 MemoryRead8(u32 vaddr) override {
37 CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); 25 CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
38 return memory.Read8(vaddr); 26 return m_memory.Read8(vaddr);
39 } 27 }
40 u16 MemoryRead16(u32 vaddr) override { 28 u16 MemoryRead16(u32 vaddr) override {
41 CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); 29 CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
42 return memory.Read16(vaddr); 30 return m_memory.Read16(vaddr);
43 } 31 }
44 u32 MemoryRead32(u32 vaddr) override { 32 u32 MemoryRead32(u32 vaddr) override {
45 CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); 33 CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
46 return memory.Read32(vaddr); 34 return m_memory.Read32(vaddr);
47 } 35 }
48 u64 MemoryRead64(u32 vaddr) override { 36 u64 MemoryRead64(u32 vaddr) override {
49 CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); 37 CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
50 return memory.Read64(vaddr); 38 return m_memory.Read64(vaddr);
51 } 39 }
52 std::optional<u32> MemoryReadCode(u32 vaddr) override { 40 std::optional<u32> MemoryReadCode(u32 vaddr) override {
53 if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { 41 if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
54 return std::nullopt; 42 return std::nullopt;
55 } 43 }
56 return memory.Read32(vaddr); 44 return m_memory.Read32(vaddr);
57 } 45 }
58 46
59 void MemoryWrite8(u32 vaddr, u8 value) override { 47 void MemoryWrite8(u32 vaddr, u8 value) override {
60 if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { 48 if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
61 memory.Write8(vaddr, value); 49 m_memory.Write8(vaddr, value);
62 } 50 }
63 } 51 }
64 void MemoryWrite16(u32 vaddr, u16 value) override { 52 void MemoryWrite16(u32 vaddr, u16 value) override {
65 if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { 53 if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
66 memory.Write16(vaddr, value); 54 m_memory.Write16(vaddr, value);
67 } 55 }
68 } 56 }
69 void MemoryWrite32(u32 vaddr, u32 value) override { 57 void MemoryWrite32(u32 vaddr, u32 value) override {
70 if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { 58 if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
71 memory.Write32(vaddr, value); 59 m_memory.Write32(vaddr, value);
72 } 60 }
73 } 61 }
74 void MemoryWrite64(u32 vaddr, u64 value) override { 62 void MemoryWrite64(u32 vaddr, u64 value) override {
75 if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { 63 if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
76 memory.Write64(vaddr, value); 64 m_memory.Write64(vaddr, value);
77 } 65 }
78 } 66 }
79 67
80 bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override { 68 bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override {
81 return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && 69 return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
82 memory.WriteExclusive8(vaddr, value, expected); 70 m_memory.WriteExclusive8(vaddr, value, expected);
83 } 71 }
84 bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override { 72 bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override {
85 return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && 73 return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) &&
86 memory.WriteExclusive16(vaddr, value, expected); 74 m_memory.WriteExclusive16(vaddr, value, expected);
87 } 75 }
88 bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override { 76 bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override {
89 return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && 77 return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) &&
90 memory.WriteExclusive32(vaddr, value, expected); 78 m_memory.WriteExclusive32(vaddr, value, expected);
91 } 79 }
92 bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override { 80 bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override {
93 return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && 81 return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) &&
94 memory.WriteExclusive64(vaddr, value, expected); 82 m_memory.WriteExclusive64(vaddr, value, expected);
95 } 83 }
96 84
97 void InterpreterFallback(u32 pc, std::size_t num_instructions) override { 85 void InterpreterFallback(u32 pc, std::size_t num_instructions) override {
98 parent.LogBacktrace(); 86 m_parent.LogBacktrace(m_process);
99 LOG_ERROR(Core_ARM, 87 LOG_ERROR(Core_ARM,
100 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, 88 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
101 num_instructions, memory.Read32(pc)); 89 num_instructions, m_memory.Read32(pc));
102 } 90 }
103 91
104 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { 92 void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
@@ -108,73 +96,64 @@ public:
108 ReturnException(pc, PrefetchAbort); 96 ReturnException(pc, PrefetchAbort);
109 return; 97 return;
110 default: 98 default:
111 if (debugger_enabled) { 99 if (m_debugger_enabled) {
112 ReturnException(pc, InstructionBreakpoint); 100 ReturnException(pc, InstructionBreakpoint);
113 return; 101 return;
114 } 102 }
115 103
116 parent.LogBacktrace(); 104 m_parent.LogBacktrace(m_process);
117 LOG_CRITICAL(Core_ARM, 105 LOG_CRITICAL(Core_ARM,
118 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", 106 "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
119 exception, pc, memory.Read32(pc), parent.IsInThumbMode()); 107 exception, pc, m_memory.Read32(pc), m_parent.IsInThumbMode());
120 } 108 }
121 } 109 }
122 110
123 void CallSVC(u32 swi) override { 111 void CallSVC(u32 swi) override {
124 parent.svc_swi = swi; 112 m_parent.m_svc_swi = swi;
125 parent.jit.load()->HaltExecution(SupervisorCall); 113 m_parent.m_jit->HaltExecution(SupervisorCall);
126 } 114 }
127 115
128 void AddTicks(u64 ticks) override { 116 void AddTicks(u64 ticks) override {
129 if (parent.uses_wall_clock) { 117 ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled");
130 return;
131 }
132 118
133 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 119 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
134 // rough approximation of the amount of executed ticks in the system, it may be thrown off 120 // rough approximation of the amount of executed ticks in the system, it may be thrown off
135 // if not all cores are doing a similar amount of work. Instead of doing this, we should 121 // if not all cores are doing a similar amount of work. Instead of doing this, we should
136 // device a way so that timing is consistent across all cores without increasing the ticks 4 122 // device a way so that timing is consistent across all cores without increasing the ticks 4
137 // times. 123 // times.
138 u64 amortized_ticks = 124 u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
139 (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
140 // Always execute at least one tick. 125 // Always execute at least one tick.
141 amortized_ticks = std::max<u64>(amortized_ticks, 1); 126 amortized_ticks = std::max<u64>(amortized_ticks, 1);
142 127
143 parent.system.CoreTiming().AddTicks(amortized_ticks); 128 m_parent.m_system.CoreTiming().AddTicks(amortized_ticks);
144 num_interpreted_instructions = 0;
145 } 129 }
146 130
147 u64 GetTicksRemaining() override { 131 u64 GetTicksRemaining() override {
148 if (parent.uses_wall_clock) { 132 ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled");
149 if (!IsInterrupted()) {
150 return minimum_run_cycles;
151 }
152 return 0U;
153 }
154 133
155 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 134 return std::max<s64>(m_parent.m_system.CoreTiming().GetDowncount(), 0);
156 } 135 }
157 136
158 bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) { 137 bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
159 if (!check_memory_access) { 138 if (!m_check_memory_access) {
160 return true; 139 return true;
161 } 140 }
162 141
163 if (!memory.IsValidVirtualAddressRange(addr, size)) { 142 if (!m_memory.IsValidVirtualAddressRange(addr, size)) {
164 LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}", 143 LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
165 addr); 144 addr);
166 parent.jit.load()->HaltExecution(PrefetchAbort); 145 m_parent.m_jit->HaltExecution(PrefetchAbort);
167 return false; 146 return false;
168 } 147 }
169 148
170 if (!debugger_enabled) { 149 if (!m_debugger_enabled) {
171 return true; 150 return true;
172 } 151 }
173 152
174 const auto match{parent.MatchingWatchpoint(addr, size, type)}; 153 const auto match{m_parent.MatchingWatchpoint(addr, size, type)};
175 if (match) { 154 if (match) {
176 parent.halted_watchpoint = match; 155 m_parent.m_halted_watchpoint = match;
177 parent.jit.load()->HaltExecution(DataAbort); 156 m_parent.m_jit->HaltExecution(DataAbort);
178 return false; 157 return false;
179 } 158 }
180 159
@@ -182,32 +161,31 @@ public:
182 } 161 }
183 162
184 void ReturnException(u32 pc, Dynarmic::HaltReason hr) { 163 void ReturnException(u32 pc, Dynarmic::HaltReason hr) {
185 parent.SaveContext(parent.breakpoint_context); 164 m_parent.GetContext(m_parent.m_breakpoint_context);
186 parent.breakpoint_context.cpu_registers[15] = pc; 165 m_parent.m_breakpoint_context.pc = pc;
187 parent.jit.load()->HaltExecution(hr); 166 m_parent.m_breakpoint_context.r[15] = pc;
188 } 167 m_parent.m_jit->HaltExecution(hr);
189
190 bool IsInterrupted() {
191 return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted();
192 } 168 }
193 169
194 ARM_Dynarmic_32& parent; 170 ArmDynarmic32& m_parent;
195 Core::Memory::Memory& memory; 171 Core::Memory::Memory& m_memory;
196 std::size_t num_interpreted_instructions{}; 172 const Kernel::KProcess* m_process{};
197 const bool debugger_enabled{}; 173 const bool m_debugger_enabled{};
198 const bool check_memory_access{}; 174 const bool m_check_memory_access{};
199 static constexpr u64 minimum_run_cycles = 10000U; 175 static constexpr u64 MinimumRunCycles = 10000U;
200}; 176};
201 177
202std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const { 178std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* page_table) const {
203 Dynarmic::A32::UserConfig config; 179 Dynarmic::A32::UserConfig config;
204 config.callbacks = cb.get(); 180 config.callbacks = m_cb.get();
205 config.coprocessors[15] = cp15; 181 config.coprocessors[15] = m_cp15;
206 config.define_unpredictable_behaviour = true; 182 config.define_unpredictable_behaviour = true;
207 static constexpr std::size_t YUZU_PAGEBITS = 12; 183
208 static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - YUZU_PAGEBITS);
209 if (page_table) { 184 if (page_table) {
210 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( 185 constexpr size_t PageBits = 12;
186 constexpr size_t NumPageTableEntries = 1 << (32 - PageBits);
187
188 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NumPageTableEntries>*>(
211 page_table->pointers.data()); 189 page_table->pointers.data());
212 config.absolute_offset_page_table = true; 190 config.absolute_offset_page_table = true;
213 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS; 191 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
@@ -221,12 +199,12 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
221 } 199 }
222 200
223 // Multi-process state 201 // Multi-process state
224 config.processor_id = core_index; 202 config.processor_id = m_core_index;
225 config.global_monitor = &exclusive_monitor.monitor; 203 config.global_monitor = &m_exclusive_monitor.monitor;
226 204
227 // Timing 205 // Timing
228 config.wall_clock_cntpct = uses_wall_clock; 206 config.wall_clock_cntpct = m_uses_wall_clock;
229 config.enable_cycle_counting = true; 207 config.enable_cycle_counting = !m_uses_wall_clock;
230 208
231 // Code cache size 209 // Code cache size
232#ifdef ARCHITECTURE_arm64 210#ifdef ARCHITECTURE_arm64
@@ -236,7 +214,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
236#endif 214#endif
237 215
238 // Allow memory fault handling to work 216 // Allow memory fault handling to work
239 if (system.DebuggerEnabled()) { 217 if (m_system.DebuggerEnabled()) {
240 config.check_halt_on_memory_access = true; 218 config.check_halt_on_memory_access = true;
241 } 219 }
242 220
@@ -325,137 +303,140 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
325 return std::make_unique<Dynarmic::A32::Jit>(config); 303 return std::make_unique<Dynarmic::A32::Jit>(config);
326} 304}
327 305
328HaltReason ARM_Dynarmic_32::RunJit() { 306static std::pair<u32, u32> FpscrToFpsrFpcr(u32 fpscr) {
329 return TranslateHaltReason(jit.load()->Run()); 307 // FPSCR bits [31:27] are mapped to FPSR[31:27].
308 // FPSCR bit [7] is mapped to FPSR[7].
309 // FPSCR bits [4:0] are mapped to FPSR[4:0].
310 const u32 nzcv = fpscr & 0xf8000000;
311 const u32 idc = fpscr & 0x80;
312 const u32 fiq = fpscr & 0x1f;
313 const u32 fpsr = nzcv | idc | fiq;
314
315 // FPSCR bits [26:15] are mapped to FPCR[26:15].
316 // FPSCR bits [12:8] are mapped to FPCR[12:8].
317 const u32 round = fpscr & 0x7ff8000;
318 const u32 trap = fpscr & 0x1f00;
319 const u32 fpcr = round | trap;
320
321 return {fpsr, fpcr};
330} 322}
331 323
332HaltReason ARM_Dynarmic_32::StepJit() { 324static u32 FpsrFpcrToFpscr(u64 fpsr, u64 fpcr) {
333 return TranslateHaltReason(jit.load()->Step()); 325 auto [s, c] = FpscrToFpsrFpcr(static_cast<u32>(fpsr | fpcr));
326 return s | c;
334} 327}
335 328
336u32 ARM_Dynarmic_32::GetSvcNumber() const { 329bool ArmDynarmic32::IsInThumbMode() const {
337 return svc_swi; 330 return (m_jit->Cpsr() & 0x20) != 0;
338} 331}
339 332
340const Kernel::DebugWatchpoint* ARM_Dynarmic_32::HaltedWatchpoint() const { 333HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
341 return halted_watchpoint; 334 m_jit->ClearExclusiveState();
335 return TranslateHaltReason(m_jit->Run());
342} 336}
343 337
344void ARM_Dynarmic_32::RewindBreakpointInstruction() { 338HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
345 LoadContext(breakpoint_context); 339 m_jit->ClearExclusiveState();
340 return TranslateHaltReason(m_jit->Step());
346} 341}
347 342
348ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, 343u32 ArmDynarmic32::GetSvcNumber() const {
349 DynarmicExclusiveMonitor& exclusive_monitor_, 344 return m_svc_swi;
350 std::size_t core_index_) 345}
351 : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
352 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
353 exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
354 346
355ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; 347void ArmDynarmic32::GetSvcArguments(std::span<uint64_t, 8> args) const {
348 Dynarmic::A32::Jit& j = *m_jit;
349 auto& gpr = j.Regs();
356 350
357void ARM_Dynarmic_32::SetPC(u64 pc) { 351 for (size_t i = 0; i < 8; i++) {
358 jit.load()->Regs()[15] = static_cast<u32>(pc); 352 args[i] = gpr[i];
353 }
359} 354}
360 355
361u64 ARM_Dynarmic_32::GetPC() const { 356void ArmDynarmic32::SetSvcArguments(std::span<const uint64_t, 8> args) {
362 return jit.load()->Regs()[15]; 357 Dynarmic::A32::Jit& j = *m_jit;
363} 358 auto& gpr = j.Regs();
364 359
365u64 ARM_Dynarmic_32::GetSP() const { 360 for (size_t i = 0; i < 8; i++) {
366 return jit.load()->Regs()[13]; 361 gpr[i] = static_cast<u32>(args[i]);
362 }
367} 363}
368 364
369u64 ARM_Dynarmic_32::GetReg(int index) const { 365const Kernel::DebugWatchpoint* ArmDynarmic32::HaltedWatchpoint() const {
370 return jit.load()->Regs()[index]; 366 return m_halted_watchpoint;
371} 367}
372 368
373void ARM_Dynarmic_32::SetReg(int index, u64 value) { 369void ArmDynarmic32::RewindBreakpointInstruction() {
374 jit.load()->Regs()[index] = static_cast<u32>(value); 370 this->SetContext(m_breakpoint_context);
375} 371}
376 372
377u128 ARM_Dynarmic_32::GetVectorReg(int index) const { 373ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
378 return {}; 374 DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
375 : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
376 m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),
377 m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
378 auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
379 m_jit = MakeJit(&page_table_impl);
379} 380}
380 381
381void ARM_Dynarmic_32::SetVectorReg(int index, u128 value) {} 382ArmDynarmic32::~ArmDynarmic32() = default;
382 383
383u32 ARM_Dynarmic_32::GetPSTATE() const { 384void ArmDynarmic32::SetTpidrroEl0(u64 value) {
384 return jit.load()->Cpsr(); 385 m_cp15->uro = static_cast<u32>(value);
385} 386}
386 387
387void ARM_Dynarmic_32::SetPSTATE(u32 cpsr) { 388void ArmDynarmic32::GetContext(Kernel::Svc::ThreadContext& ctx) const {
388 jit.load()->SetCpsr(cpsr); 389 Dynarmic::A32::Jit& j = *m_jit;
389} 390 auto& gpr = j.Regs();
391 auto& fpr = j.ExtRegs();
390 392
391u64 ARM_Dynarmic_32::GetTlsAddress() const { 393 for (size_t i = 0; i < 16; i++) {
392 return cp15->uro; 394 ctx.r[i] = gpr[i];
393} 395 }
394 396
395void ARM_Dynarmic_32::SetTlsAddress(u64 address) { 397 ctx.fp = gpr[11];
396 cp15->uro = static_cast<u32>(address); 398 ctx.sp = gpr[13];
397} 399 ctx.lr = gpr[14];
400 ctx.pc = gpr[15];
401 ctx.pstate = j.Cpsr();
398 402
399u64 ARM_Dynarmic_32::GetTPIDR_EL0() const { 403 static_assert(sizeof(fpr) <= sizeof(ctx.v));
400 return cp15->uprw; 404 std::memcpy(ctx.v.data(), &fpr, sizeof(fpr));
401}
402 405
403void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { 406 auto [fpsr, fpcr] = FpscrToFpsrFpcr(j.Fpscr());
404 cp15->uprw = static_cast<u32>(value); 407 ctx.fpcr = fpcr;
408 ctx.fpsr = fpsr;
409 ctx.tpidr = m_cp15->uprw;
405} 410}
406 411
407void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) const { 412void ArmDynarmic32::SetContext(const Kernel::Svc::ThreadContext& ctx) {
408 Dynarmic::A32::Jit* j = jit.load(); 413 Dynarmic::A32::Jit& j = *m_jit;
409 ctx.cpu_registers = j->Regs(); 414 auto& gpr = j.Regs();
410 ctx.extension_registers = j->ExtRegs(); 415 auto& fpr = j.ExtRegs();
411 ctx.cpsr = j->Cpsr();
412 ctx.fpscr = j->Fpscr();
413}
414 416
415void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { 417 for (size_t i = 0; i < 16; i++) {
416 Dynarmic::A32::Jit* j = jit.load(); 418 gpr[i] = static_cast<u32>(ctx.r[i]);
417 j->Regs() = ctx.cpu_registers; 419 }
418 j->ExtRegs() = ctx.extension_registers;
419 j->SetCpsr(ctx.cpsr);
420 j->SetFpscr(ctx.fpscr);
421}
422 420
423void ARM_Dynarmic_32::SignalInterrupt() { 421 j.SetCpsr(ctx.pstate);
424 jit.load()->HaltExecution(BreakLoop);
425}
426 422
427void ARM_Dynarmic_32::ClearInterrupt() { 423 static_assert(sizeof(fpr) <= sizeof(ctx.v));
428 jit.load()->ClearHalt(BreakLoop); 424 std::memcpy(&fpr, ctx.v.data(), sizeof(fpr));
429}
430 425
431void ARM_Dynarmic_32::ClearInstructionCache() { 426 j.SetFpscr(FpsrFpcrToFpscr(ctx.fpsr, ctx.fpcr));
432 jit.load()->ClearCache(); 427 m_cp15->uprw = static_cast<u32>(ctx.tpidr);
433} 428}
434 429
435void ARM_Dynarmic_32::InvalidateCacheRange(u64 addr, std::size_t size) { 430void ArmDynarmic32::SignalInterrupt(Kernel::KThread* thread) {
436 jit.load()->InvalidateCacheRange(static_cast<u32>(addr), size); 431 m_jit->HaltExecution(BreakLoop);
437} 432}
438 433
439void ARM_Dynarmic_32::ClearExclusiveState() { 434void ArmDynarmic32::ClearInstructionCache() {
440 jit.load()->ClearExclusiveState(); 435 m_jit->ClearCache();
441} 436}
442 437
443void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, 438void ArmDynarmic32::InvalidateCacheRange(u64 addr, std::size_t size) {
444 std::size_t new_address_space_size_in_bits) { 439 m_jit->InvalidateCacheRange(static_cast<u32>(addr), size);
445 ThreadContext32 ctx{};
446 SaveContext(ctx);
447
448 auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
449 auto iter = jit_cache.find(key);
450 if (iter != jit_cache.end()) {
451 jit.store(iter->second.get());
452 LoadContext(ctx);
453 return;
454 }
455 std::shared_ptr new_jit = MakeJit(&page_table);
456 jit.store(new_jit.get());
457 LoadContext(ctx);
458 jit_cache.emplace(key, std::move(new_jit));
459} 440}
460 441
461} // namespace Core 442} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 92fb3f836..185ac7cbf 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -3,14 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <atomic>
7#include <memory>
8#include <unordered_map>
9
10#include <dynarmic/interface/A32/a32.h> 6#include <dynarmic/interface/A32/a32.h>
11#include <dynarmic/interface/A64/a64.h> 7
12#include "common/common_types.h"
13#include "common/hash.h"
14#include "core/arm/arm_interface.h" 8#include "core/arm/arm_interface.h"
15#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" 9#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
16 10
@@ -20,89 +14,63 @@ class Memory;
20 14
21namespace Core { 15namespace Core {
22 16
23class CPUInterruptHandler;
24class DynarmicCallbacks32; 17class DynarmicCallbacks32;
25class DynarmicCP15; 18class DynarmicCP15;
26class DynarmicExclusiveMonitor;
27class System; 19class System;
28 20
29class ARM_Dynarmic_32 final : public ARM_Interface { 21class ArmDynarmic32 final : public ArmInterface {
30public: 22public:
31 ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, 23 ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
32 DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); 24 DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
33 ~ARM_Dynarmic_32() override; 25 ~ArmDynarmic32() override;
34
35 void SetPC(u64 pc) override;
36 u64 GetPC() const override;
37 u64 GetSP() const override;
38 u64 GetReg(int index) const override;
39 void SetReg(int index, u64 value) override;
40 u128 GetVectorReg(int index) const override;
41 void SetVectorReg(int index, u128 value) override;
42 u32 GetPSTATE() const override;
43 void SetPSTATE(u32 pstate) override;
44 u64 GetTlsAddress() const override;
45 void SetTlsAddress(u64 address) override;
46 void SetTPIDR_EL0(u64 value) override;
47 u64 GetTPIDR_EL0() const override;
48
49 bool IsInThumbMode() const {
50 return (GetPSTATE() & 0x20) != 0;
51 }
52 26
53 Architecture GetArchitecture() const override { 27 Architecture GetArchitecture() const override {
54 return Architecture::Aarch32; 28 return Architecture::AArch32;
55 } 29 }
56 void SaveContext(ThreadContext32& ctx) const override;
57 void SaveContext(ThreadContext64& ctx) const override {}
58 void LoadContext(const ThreadContext32& ctx) override;
59 void LoadContext(const ThreadContext64& ctx) override {}
60 30
61 void SignalInterrupt() override; 31 bool IsInThumbMode() const;
62 void ClearInterrupt() override; 32
63 void ClearExclusiveState() override; 33 HaltReason RunThread(Kernel::KThread* thread) override;
34 HaltReason StepThread(Kernel::KThread* thread) override;
35
36 void GetContext(Kernel::Svc::ThreadContext& ctx) const override;
37 void SetContext(const Kernel::Svc::ThreadContext& ctx) override;
38 void SetTpidrroEl0(u64 value) override;
39
40 void GetSvcArguments(std::span<uint64_t, 8> args) const override;
41 void SetSvcArguments(std::span<const uint64_t, 8> args) override;
42 u32 GetSvcNumber() const override;
64 43
44 void SignalInterrupt(Kernel::KThread* thread) override;
65 void ClearInstructionCache() override; 45 void ClearInstructionCache() override;
66 void InvalidateCacheRange(u64 addr, std::size_t size) override; 46 void InvalidateCacheRange(u64 addr, std::size_t size) override;
67 void PageTableChanged(Common::PageTable& new_page_table,
68 std::size_t new_address_space_size_in_bits) override;
69 47
70protected: 48protected:
71 HaltReason RunJit() override;
72 HaltReason StepJit() override;
73 u32 GetSvcNumber() const override;
74 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; 49 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
75 void RewindBreakpointInstruction() override; 50 void RewindBreakpointInstruction() override;
76 51
77private: 52private:
78 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; 53 System& m_system;
79 54 DynarmicExclusiveMonitor& m_exclusive_monitor;
80 static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc);
81
82 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
83 using JitCacheType =
84 std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>;
85 55
56private:
86 friend class DynarmicCallbacks32; 57 friend class DynarmicCallbacks32;
87 friend class DynarmicCP15; 58 friend class DynarmicCP15;
88 59
89 std::unique_ptr<DynarmicCallbacks32> cb; 60 std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const;
90 JitCacheType jit_cache;
91 std::shared_ptr<DynarmicCP15> cp15;
92 std::size_t core_index;
93 DynarmicExclusiveMonitor& exclusive_monitor;
94 61
95 std::shared_ptr<Dynarmic::A32::Jit> null_jit; 62 std::unique_ptr<DynarmicCallbacks32> m_cb{};
63 std::shared_ptr<DynarmicCP15> m_cp15{};
64 std::size_t m_core_index{};
96 65
97 // A raw pointer here is fine; we never delete Jit instances. 66 std::shared_ptr<Dynarmic::A32::Jit> m_jit{};
98 std::atomic<Dynarmic::A32::Jit*> jit;
99 67
100 // SVC callback 68 // SVC callback
101 u32 svc_swi{}; 69 u32 m_svc_swi{};
102 70
103 // Watchpoint info 71 // Watchpoint info
104 const Kernel::DebugWatchpoint* halted_watchpoint; 72 const Kernel::DebugWatchpoint* m_halted_watchpoint{};
105 ThreadContext32 breakpoint_context; 73 Kernel::Svc::ThreadContext m_breakpoint_context{};
106}; 74};
107 75
108} // namespace Core 76} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 2e3674b6d..dff14756e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -1,25 +1,12 @@
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 <cinttypes>
5#include <memory>
6#include <dynarmic/interface/A64/a64.h>
7#include <dynarmic/interface/A64/config.h>
8#include "common/assert.h"
9#include "common/literals.h"
10#include "common/logging/log.h"
11#include "common/page_table.h"
12#include "common/settings.h" 4#include "common/settings.h"
13#include "core/arm/dynarmic/arm_dynarmic.h" 5#include "core/arm/dynarmic/arm_dynarmic.h"
14#include "core/arm/dynarmic/arm_dynarmic_64.h" 6#include "core/arm/dynarmic/arm_dynarmic_64.h"
15#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" 7#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
16#include "core/core.h"
17#include "core/core_timing.h" 8#include "core/core_timing.h"
18#include "core/debugger/debugger.h"
19#include "core/hardware_properties.h"
20#include "core/hle/kernel/k_process.h" 9#include "core/hle/kernel/k_process.h"
21#include "core/hle/kernel/svc.h"
22#include "core/memory.h"
23 10
24namespace Core { 11namespace Core {
25 12
@@ -28,92 +15,92 @@ using namespace Common::Literals;
28 15
29class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { 16class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
30public: 17public:
31 explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) 18 explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process)
32 : parent{parent_}, memory(parent.system.ApplicationMemory()), 19 : m_parent{parent}, m_memory(process->GetMemory()),
33 debugger_enabled{parent.system.DebuggerEnabled()}, 20 m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
34 check_memory_access{debugger_enabled || 21 m_check_memory_access{m_debugger_enabled ||
35 !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} 22 !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {}
36 23
37 u8 MemoryRead8(u64 vaddr) override { 24 u8 MemoryRead8(u64 vaddr) override {
38 CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); 25 CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
39 return memory.Read8(vaddr); 26 return m_memory.Read8(vaddr);
40 } 27 }
41 u16 MemoryRead16(u64 vaddr) override { 28 u16 MemoryRead16(u64 vaddr) override {
42 CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); 29 CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
43 return memory.Read16(vaddr); 30 return m_memory.Read16(vaddr);
44 } 31 }
45 u32 MemoryRead32(u64 vaddr) override { 32 u32 MemoryRead32(u64 vaddr) override {
46 CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); 33 CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
47 return memory.Read32(vaddr); 34 return m_memory.Read32(vaddr);
48 } 35 }
49 u64 MemoryRead64(u64 vaddr) override { 36 u64 MemoryRead64(u64 vaddr) override {
50 CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); 37 CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
51 return memory.Read64(vaddr); 38 return m_memory.Read64(vaddr);
52 } 39 }
53 Vector MemoryRead128(u64 vaddr) override { 40 Vector MemoryRead128(u64 vaddr) override {
54 CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); 41 CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
55 return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; 42 return {m_memory.Read64(vaddr), m_memory.Read64(vaddr + 8)};
56 } 43 }
57 std::optional<u32> MemoryReadCode(u64 vaddr) override { 44 std::optional<u32> MemoryReadCode(u64 vaddr) override {
58 if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { 45 if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) {
59 return std::nullopt; 46 return std::nullopt;
60 } 47 }
61 return memory.Read32(vaddr); 48 return m_memory.Read32(vaddr);
62 } 49 }
63 50
64 void MemoryWrite8(u64 vaddr, u8 value) override { 51 void MemoryWrite8(u64 vaddr, u8 value) override {
65 if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { 52 if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
66 memory.Write8(vaddr, value); 53 m_memory.Write8(vaddr, value);
67 } 54 }
68 } 55 }
69 void MemoryWrite16(u64 vaddr, u16 value) override { 56 void MemoryWrite16(u64 vaddr, u16 value) override {
70 if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { 57 if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
71 memory.Write16(vaddr, value); 58 m_memory.Write16(vaddr, value);
72 } 59 }
73 } 60 }
74 void MemoryWrite32(u64 vaddr, u32 value) override { 61 void MemoryWrite32(u64 vaddr, u32 value) override {
75 if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { 62 if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
76 memory.Write32(vaddr, value); 63 m_memory.Write32(vaddr, value);
77 } 64 }
78 } 65 }
79 void MemoryWrite64(u64 vaddr, u64 value) override { 66 void MemoryWrite64(u64 vaddr, u64 value) override {
80 if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { 67 if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
81 memory.Write64(vaddr, value); 68 m_memory.Write64(vaddr, value);
82 } 69 }
83 } 70 }
84 void MemoryWrite128(u64 vaddr, Vector value) override { 71 void MemoryWrite128(u64 vaddr, Vector value) override {
85 if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) { 72 if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) {
86 memory.Write64(vaddr, value[0]); 73 m_memory.Write64(vaddr, value[0]);
87 memory.Write64(vaddr + 8, value[1]); 74 m_memory.Write64(vaddr + 8, value[1]);
88 } 75 }
89 } 76 }
90 77
91 bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override { 78 bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override {
92 return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && 79 return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
93 memory.WriteExclusive8(vaddr, value, expected); 80 m_memory.WriteExclusive8(vaddr, value, expected);
94 } 81 }
95 bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override { 82 bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override {
96 return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && 83 return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) &&
97 memory.WriteExclusive16(vaddr, value, expected); 84 m_memory.WriteExclusive16(vaddr, value, expected);
98 } 85 }
99 bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override { 86 bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override {
100 return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && 87 return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) &&
101 memory.WriteExclusive32(vaddr, value, expected); 88 m_memory.WriteExclusive32(vaddr, value, expected);
102 } 89 }
103 bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override { 90 bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override {
104 return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && 91 return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) &&
105 memory.WriteExclusive64(vaddr, value, expected); 92 m_memory.WriteExclusive64(vaddr, value, expected);
106 } 93 }
107 bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override { 94 bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override {
108 return CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write) && 95 return CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write) &&
109 memory.WriteExclusive128(vaddr, value, expected); 96 m_memory.WriteExclusive128(vaddr, value, expected);
110 } 97 }
111 98
112 void InterpreterFallback(u64 pc, std::size_t num_instructions) override { 99 void InterpreterFallback(u64 pc, std::size_t num_instructions) override {
113 parent.LogBacktrace(); 100 m_parent.LogBacktrace(m_process);
114 LOG_ERROR(Core_ARM, 101 LOG_ERROR(Core_ARM,
115 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, 102 "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc,
116 num_instructions, memory.Read32(pc)); 103 num_instructions, m_memory.Read32(pc));
117 ReturnException(pc, PrefetchAbort); 104 ReturnException(pc, PrefetchAbort);
118 } 105 }
119 106
@@ -124,11 +111,11 @@ public:
124 static constexpr u64 ICACHE_LINE_SIZE = 64; 111 static constexpr u64 ICACHE_LINE_SIZE = 64;
125 112
126 const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); 113 const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1);
127 parent.system.InvalidateCpuInstructionCacheRange(cache_line_start, ICACHE_LINE_SIZE); 114 m_parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE);
128 break; 115 break;
129 } 116 }
130 case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: 117 case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU:
131 parent.system.InvalidateCpuInstructionCaches(); 118 m_parent.ClearInstructionCache();
132 break; 119 break;
133 case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: 120 case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable:
134 default: 121 default:
@@ -136,7 +123,7 @@ public:
136 break; 123 break;
137 } 124 }
138 125
139 parent.jit.load()->HaltExecution(Dynarmic::HaltReason::CacheInvalidation); 126 m_parent.m_jit->HaltExecution(Dynarmic::HaltReason::CacheInvalidation);
140 } 127 }
141 128
142 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { 129 void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
@@ -152,26 +139,24 @@ public:
152 ReturnException(pc, PrefetchAbort); 139 ReturnException(pc, PrefetchAbort);
153 return; 140 return;
154 default: 141 default:
155 if (debugger_enabled) { 142 if (m_debugger_enabled) {
156 ReturnException(pc, InstructionBreakpoint); 143 ReturnException(pc, InstructionBreakpoint);
157 return; 144 return;
158 } 145 }
159 146
160 parent.LogBacktrace(); 147 m_parent.LogBacktrace(m_process);
161 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", 148 LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
162 static_cast<std::size_t>(exception), pc, memory.Read32(pc)); 149 static_cast<std::size_t>(exception), pc, m_memory.Read32(pc));
163 } 150 }
164 } 151 }
165 152
166 void CallSVC(u32 swi) override { 153 void CallSVC(u32 svc) override {
167 parent.svc_swi = swi; 154 m_parent.m_svc = svc;
168 parent.jit.load()->HaltExecution(SupervisorCall); 155 m_parent.m_jit->HaltExecution(SupervisorCall);
169 } 156 }
170 157
171 void AddTicks(u64 ticks) override { 158 void AddTicks(u64 ticks) override {
172 if (parent.uses_wall_clock) { 159 ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled");
173 return;
174 }
175 160
176 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 161 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
177 // rough approximation of the amount of executed ticks in the system, it may be thrown off 162 // rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -182,44 +167,39 @@ public:
182 // Always execute at least one tick. 167 // Always execute at least one tick.
183 amortized_ticks = std::max<u64>(amortized_ticks, 1); 168 amortized_ticks = std::max<u64>(amortized_ticks, 1);
184 169
185 parent.system.CoreTiming().AddTicks(amortized_ticks); 170 m_parent.m_system.CoreTiming().AddTicks(amortized_ticks);
186 } 171 }
187 172
188 u64 GetTicksRemaining() override { 173 u64 GetTicksRemaining() override {
189 if (parent.uses_wall_clock) { 174 ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled");
190 if (!IsInterrupted()) {
191 return minimum_run_cycles;
192 }
193 return 0U;
194 }
195 175
196 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 176 return std::max<s64>(m_parent.m_system.CoreTiming().GetDowncount(), 0);
197 } 177 }
198 178
199 u64 GetCNTPCT() override { 179 u64 GetCNTPCT() override {
200 return parent.system.CoreTiming().GetClockTicks(); 180 return m_parent.m_system.CoreTiming().GetClockTicks();
201 } 181 }
202 182
203 bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) { 183 bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) {
204 if (!check_memory_access) { 184 if (!m_check_memory_access) {
205 return true; 185 return true;
206 } 186 }
207 187
208 if (!memory.IsValidVirtualAddressRange(addr, size)) { 188 if (!m_memory.IsValidVirtualAddressRange(addr, size)) {
209 LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}", 189 LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}",
210 addr); 190 addr);
211 parent.jit.load()->HaltExecution(PrefetchAbort); 191 m_parent.m_jit->HaltExecution(PrefetchAbort);
212 return false; 192 return false;
213 } 193 }
214 194
215 if (!debugger_enabled) { 195 if (!m_debugger_enabled) {
216 return true; 196 return true;
217 } 197 }
218 198
219 const auto match{parent.MatchingWatchpoint(addr, size, type)}; 199 const auto match{m_parent.MatchingWatchpoint(addr, size, type)};
220 if (match) { 200 if (match) {
221 parent.halted_watchpoint = match; 201 m_parent.m_halted_watchpoint = match;
222 parent.jit.load()->HaltExecution(DataAbort); 202 m_parent.m_jit->HaltExecution(DataAbort);
223 return false; 203 return false;
224 } 204 }
225 205
@@ -227,30 +207,27 @@ public:
227 } 207 }
228 208
229 void ReturnException(u64 pc, Dynarmic::HaltReason hr) { 209 void ReturnException(u64 pc, Dynarmic::HaltReason hr) {
230 parent.SaveContext(parent.breakpoint_context); 210 m_parent.GetContext(m_parent.m_breakpoint_context);
231 parent.breakpoint_context.pc = pc; 211 m_parent.m_breakpoint_context.pc = pc;
232 parent.jit.load()->HaltExecution(hr); 212 m_parent.m_jit->HaltExecution(hr);
233 } 213 }
234 214
235 bool IsInterrupted() { 215 ArmDynarmic64& m_parent;
236 return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted(); 216 Core::Memory::Memory& m_memory;
237 } 217 u64 m_tpidrro_el0{};
238 218 u64 m_tpidr_el0{};
239 ARM_Dynarmic_64& parent; 219 const Kernel::KProcess* m_process{};
240 Core::Memory::Memory& memory; 220 const bool m_debugger_enabled{};
241 u64 tpidrro_el0 = 0; 221 const bool m_check_memory_access{};
242 u64 tpidr_el0 = 0; 222 static constexpr u64 MinimumRunCycles = 10000U;
243 const bool debugger_enabled{};
244 const bool check_memory_access{};
245 static constexpr u64 minimum_run_cycles = 10000U;
246}; 223};
247 224
248std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table, 225std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* page_table,
249 std::size_t address_space_bits) const { 226 std::size_t address_space_bits) const {
250 Dynarmic::A64::UserConfig config; 227 Dynarmic::A64::UserConfig config;
251 228
252 // Callbacks 229 // Callbacks
253 config.callbacks = cb.get(); 230 config.callbacks = m_cb.get();
254 231
255 // Memory 232 // Memory
256 if (page_table) { 233 if (page_table) {
@@ -271,12 +248,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
271 } 248 }
272 249
273 // Multi-process state 250 // Multi-process state
274 config.processor_id = core_index; 251 config.processor_id = m_core_index;
275 config.global_monitor = &exclusive_monitor.monitor; 252 config.global_monitor = &m_exclusive_monitor.monitor;
276 253
277 // System registers 254 // System registers
278 config.tpidrro_el0 = &cb->tpidrro_el0; 255 config.tpidrro_el0 = &m_cb->m_tpidrro_el0;
279 config.tpidr_el0 = &cb->tpidr_el0; 256 config.tpidr_el0 = &m_cb->m_tpidr_el0;
280 config.dczid_el0 = 4; 257 config.dczid_el0 = 4;
281 config.ctr_el0 = 0x8444c004; 258 config.ctr_el0 = 0x8444c004;
282 config.cntfrq_el0 = Hardware::CNTFREQ; 259 config.cntfrq_el0 = Hardware::CNTFREQ;
@@ -285,8 +262,8 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
285 config.define_unpredictable_behaviour = true; 262 config.define_unpredictable_behaviour = true;
286 263
287 // Timing 264 // Timing
288 config.wall_clock_cntpct = uses_wall_clock; 265 config.wall_clock_cntpct = m_uses_wall_clock;
289 config.enable_cycle_counting = true; 266 config.enable_cycle_counting = !m_uses_wall_clock;
290 267
291 // Code cache size 268 // Code cache size
292#ifdef ARCHITECTURE_arm64 269#ifdef ARCHITECTURE_arm64
@@ -296,7 +273,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
296#endif 273#endif
297 274
298 // Allow memory fault handling to work 275 // Allow memory fault handling to work
299 if (system.DebuggerEnabled()) { 276 if (m_system.DebuggerEnabled()) {
300 config.check_halt_on_memory_access = true; 277 config.check_halt_on_memory_access = true;
301 } 278 }
302 279
@@ -384,147 +361,112 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
384 return std::make_shared<Dynarmic::A64::Jit>(config); 361 return std::make_shared<Dynarmic::A64::Jit>(config);
385} 362}
386 363
387HaltReason ARM_Dynarmic_64::RunJit() { 364HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
388 return TranslateHaltReason(jit.load()->Run()); 365 m_jit->ClearExclusiveState();
389} 366 return TranslateHaltReason(m_jit->Run());
390
391HaltReason ARM_Dynarmic_64::StepJit() {
392 return TranslateHaltReason(jit.load()->Step());
393}
394
395u32 ARM_Dynarmic_64::GetSvcNumber() const {
396 return svc_swi;
397}
398
399const Kernel::DebugWatchpoint* ARM_Dynarmic_64::HaltedWatchpoint() const {
400 return halted_watchpoint;
401}
402
403void ARM_Dynarmic_64::RewindBreakpointInstruction() {
404 LoadContext(breakpoint_context);
405}
406
407ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
408 DynarmicExclusiveMonitor& exclusive_monitor_,
409 std::size_t core_index_)
410 : ARM_Interface{system_, uses_wall_clock_},
411 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
412 exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
413
414ARM_Dynarmic_64::~ARM_Dynarmic_64() = default;
415
416void ARM_Dynarmic_64::SetPC(u64 pc) {
417 jit.load()->SetPC(pc);
418}
419
420u64 ARM_Dynarmic_64::GetPC() const {
421 return jit.load()->GetPC();
422} 367}
423 368
424u64 ARM_Dynarmic_64::GetSP() const { 369HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
425 return jit.load()->GetSP(); 370 m_jit->ClearExclusiveState();
371 return TranslateHaltReason(m_jit->Step());
426} 372}
427 373
428u64 ARM_Dynarmic_64::GetReg(int index) const { 374u32 ArmDynarmic64::GetSvcNumber() const {
429 return jit.load()->GetRegister(index); 375 return m_svc;
430} 376}
431 377
432void ARM_Dynarmic_64::SetReg(int index, u64 value) { 378void ArmDynarmic64::GetSvcArguments(std::span<uint64_t, 8> args) const {
433 jit.load()->SetRegister(index, value); 379 Dynarmic::A64::Jit& j = *m_jit;
434}
435 380
436u128 ARM_Dynarmic_64::GetVectorReg(int index) const { 381 for (size_t i = 0; i < 8; i++) {
437 return jit.load()->GetVector(index); 382 args[i] = j.GetRegister(i);
383 }
438} 384}
439 385
440void ARM_Dynarmic_64::SetVectorReg(int index, u128 value) { 386void ArmDynarmic64::SetSvcArguments(std::span<const uint64_t, 8> args) {
441 jit.load()->SetVector(index, value); 387 Dynarmic::A64::Jit& j = *m_jit;
442}
443 388
444u32 ARM_Dynarmic_64::GetPSTATE() const { 389 for (size_t i = 0; i < 8; i++) {
445 return jit.load()->GetPstate(); 390 j.SetRegister(i, args[i]);
391 }
446} 392}
447 393
448void ARM_Dynarmic_64::SetPSTATE(u32 pstate) { 394const Kernel::DebugWatchpoint* ArmDynarmic64::HaltedWatchpoint() const {
449 jit.load()->SetPstate(pstate); 395 return m_halted_watchpoint;
450} 396}
451 397
452u64 ARM_Dynarmic_64::GetTlsAddress() const { 398void ArmDynarmic64::RewindBreakpointInstruction() {
453 return cb->tpidrro_el0; 399 this->SetContext(m_breakpoint_context);
454} 400}
455 401
456void ARM_Dynarmic_64::SetTlsAddress(u64 address) { 402ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
457 cb->tpidrro_el0 = address; 403 DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
404 : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
405 m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {
406 auto& page_table = process->GetPageTable().GetBasePageTable();
407 auto& page_table_impl = page_table.GetImpl();
408 m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
458} 409}
459 410
460u64 ARM_Dynarmic_64::GetTPIDR_EL0() const { 411ArmDynarmic64::~ArmDynarmic64() = default;
461 return cb->tpidr_el0;
462}
463 412
464void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { 413void ArmDynarmic64::SetTpidrroEl0(u64 value) {
465 cb->tpidr_el0 = value; 414 m_cb->m_tpidrro_el0 = value;
466} 415}
467 416
468void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) const { 417void ArmDynarmic64::GetContext(Kernel::Svc::ThreadContext& ctx) const {
469 Dynarmic::A64::Jit* j = jit.load(); 418 Dynarmic::A64::Jit& j = *m_jit;
470 ctx.cpu_registers = j->GetRegisters(); 419 auto gpr = j.GetRegisters();
471 ctx.sp = j->GetSP(); 420 auto fpr = j.GetVectors();
472 ctx.pc = j->GetPC();
473 ctx.pstate = j->GetPstate();
474 ctx.vector_registers = j->GetVectors();
475 ctx.fpcr = j->GetFpcr();
476 ctx.fpsr = j->GetFpsr();
477 ctx.tpidr = cb->tpidr_el0;
478}
479 421
480void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { 422 // TODO: this is inconvenient
481 Dynarmic::A64::Jit* j = jit.load(); 423 for (size_t i = 0; i < 29; i++) {
482 j->SetRegisters(ctx.cpu_registers); 424 ctx.r[i] = gpr[i];
483 j->SetSP(ctx.sp); 425 }
484 j->SetPC(ctx.pc); 426 ctx.fp = gpr[29];
485 j->SetPstate(ctx.pstate); 427 ctx.lr = gpr[30];
486 j->SetVectors(ctx.vector_registers); 428
487 j->SetFpcr(ctx.fpcr); 429 ctx.sp = j.GetSP();
488 j->SetFpsr(ctx.fpsr); 430 ctx.pc = j.GetPC();
489 SetTPIDR_EL0(ctx.tpidr); 431 ctx.pstate = j.GetPstate();
432 ctx.v = fpr;
433 ctx.fpcr = j.GetFpcr();
434 ctx.fpsr = j.GetFpsr();
435 ctx.tpidr = m_cb->m_tpidr_el0;
490} 436}
491 437
492void ARM_Dynarmic_64::SignalInterrupt() { 438void ArmDynarmic64::SetContext(const Kernel::Svc::ThreadContext& ctx) {
493 jit.load()->HaltExecution(BreakLoop); 439 Dynarmic::A64::Jit& j = *m_jit;
494}
495 440
496void ARM_Dynarmic_64::ClearInterrupt() { 441 // TODO: this is inconvenient
497 jit.load()->ClearHalt(BreakLoop); 442 std::array<u64, 31> gpr;
498}
499 443
500void ARM_Dynarmic_64::ClearInstructionCache() { 444 for (size_t i = 0; i < 29; i++) {
501 jit.load()->ClearCache(); 445 gpr[i] = ctx.r[i];
446 }
447 gpr[29] = ctx.fp;
448 gpr[30] = ctx.lr;
449
450 j.SetRegisters(gpr);
451 j.SetSP(ctx.sp);
452 j.SetPC(ctx.pc);
453 j.SetPstate(ctx.pstate);
454 j.SetVectors(ctx.v);
455 j.SetFpcr(ctx.fpcr);
456 j.SetFpsr(ctx.fpsr);
457 m_cb->m_tpidr_el0 = ctx.tpidr;
502} 458}
503 459
504void ARM_Dynarmic_64::InvalidateCacheRange(u64 addr, std::size_t size) { 460void ArmDynarmic64::SignalInterrupt(Kernel::KThread* thread) {
505 jit.load()->InvalidateCacheRange(addr, size); 461 m_jit->HaltExecution(BreakLoop);
506} 462}
507 463
508void ARM_Dynarmic_64::ClearExclusiveState() { 464void ArmDynarmic64::ClearInstructionCache() {
509 jit.load()->ClearExclusiveState(); 465 m_jit->ClearCache();
510} 466}
511 467
512void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, 468void ArmDynarmic64::InvalidateCacheRange(u64 addr, std::size_t size) {
513 std::size_t new_address_space_size_in_bits) { 469 m_jit->InvalidateCacheRange(addr, size);
514 ThreadContext64 ctx{};
515 SaveContext(ctx);
516
517 auto key = std::make_pair(&page_table, new_address_space_size_in_bits);
518 auto iter = jit_cache.find(key);
519 if (iter != jit_cache.end()) {
520 jit.store(iter->second.get());
521 LoadContext(ctx);
522 return;
523 }
524 std::shared_ptr new_jit = MakeJit(&page_table, new_address_space_size_in_bits);
525 jit.store(new_jit.get());
526 LoadContext(ctx);
527 jit_cache.emplace(key, std::move(new_jit));
528} 470}
529 471
530} // namespace Core 472} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index 2b88a08e2..4f3dd026f 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -23,76 +23,55 @@ class DynarmicCallbacks64;
23class DynarmicExclusiveMonitor; 23class DynarmicExclusiveMonitor;
24class System; 24class System;
25 25
26class ARM_Dynarmic_64 final : public ARM_Interface { 26class ArmDynarmic64 final : public ArmInterface {
27public: 27public:
28 ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, 28 ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process,
29 DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); 29 DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
30 ~ARM_Dynarmic_64() override; 30 ~ArmDynarmic64() override;
31
32 void SetPC(u64 pc) override;
33 u64 GetPC() const override;
34 u64 GetSP() const override;
35 u64 GetReg(int index) const override;
36 void SetReg(int index, u64 value) override;
37 u128 GetVectorReg(int index) const override;
38 void SetVectorReg(int index, u128 value) override;
39 u32 GetPSTATE() const override;
40 void SetPSTATE(u32 pstate) override;
41 u64 GetTlsAddress() const override;
42 void SetTlsAddress(u64 address) override;
43 void SetTPIDR_EL0(u64 value) override;
44 u64 GetTPIDR_EL0() const override;
45 31
46 Architecture GetArchitecture() const override { 32 Architecture GetArchitecture() const override {
47 return Architecture::Aarch64; 33 return Architecture::AArch64;
48 } 34 }
49 void SaveContext(ThreadContext32& ctx) const override {}
50 void SaveContext(ThreadContext64& ctx) const override;
51 void LoadContext(const ThreadContext32& ctx) override {}
52 void LoadContext(const ThreadContext64& ctx) override;
53 35
54 void SignalInterrupt() override; 36 HaltReason RunThread(Kernel::KThread* thread) override;
55 void ClearInterrupt() override; 37 HaltReason StepThread(Kernel::KThread* thread) override;
56 void ClearExclusiveState() override;
57 38
39 void GetContext(Kernel::Svc::ThreadContext& ctx) const override;
40 void SetContext(const Kernel::Svc::ThreadContext& ctx) override;
41 void SetTpidrroEl0(u64 value) override;
42
43 void GetSvcArguments(std::span<uint64_t, 8> args) const override;
44 void SetSvcArguments(std::span<const uint64_t, 8> args) override;
45 u32 GetSvcNumber() const override;
46
47 void SignalInterrupt(Kernel::KThread* thread) override;
58 void ClearInstructionCache() override; 48 void ClearInstructionCache() override;
59 void InvalidateCacheRange(u64 addr, std::size_t size) override; 49 void InvalidateCacheRange(u64 addr, std::size_t size) override;
60 void PageTableChanged(Common::PageTable& new_page_table,
61 std::size_t new_address_space_size_in_bits) override;
62 50
63protected: 51protected:
64 HaltReason RunJit() override;
65 HaltReason StepJit() override;
66 u32 GetSvcNumber() const override;
67 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; 52 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override;
68 void RewindBreakpointInstruction() override; 53 void RewindBreakpointInstruction() override;
69 54
70private: 55private:
71 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, 56 System& m_system;
72 std::size_t address_space_bits) const; 57 DynarmicExclusiveMonitor& m_exclusive_monitor;
73
74 using JitCacheKey = std::pair<Common::PageTable*, std::size_t>;
75 using JitCacheType =
76 std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>;
77 58
59private:
78 friend class DynarmicCallbacks64; 60 friend class DynarmicCallbacks64;
79 std::unique_ptr<DynarmicCallbacks64> cb;
80 JitCacheType jit_cache;
81
82 std::size_t core_index;
83 DynarmicExclusiveMonitor& exclusive_monitor;
84 61
85 std::shared_ptr<Dynarmic::A64::Jit> null_jit; 62 std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table,
63 std::size_t address_space_bits) const;
64 std::unique_ptr<DynarmicCallbacks64> m_cb{};
65 std::size_t m_core_index{};
86 66
87 // A raw pointer here is fine; we never delete Jit instances. 67 std::shared_ptr<Dynarmic::A64::Jit> m_jit{};
88 std::atomic<Dynarmic::A64::Jit*> jit;
89 68
90 // SVC callback 69 // SVC callback
91 u32 svc_swi{}; 70 u32 m_svc{};
92 71
93 // Breakpoint info 72 // Watchpoint info
94 const Kernel::DebugWatchpoint* halted_watchpoint; 73 const Kernel::DebugWatchpoint* m_halted_watchpoint{};
95 ThreadContext64 breakpoint_context; 74 Kernel::Svc::ThreadContext m_breakpoint_context{};
96}; 75};
97 76
98} // namespace Core 77} // namespace Core
diff --git a/src/core/arm/dynarmic/dynarmic_cp15.cpp b/src/core/arm/dynarmic/dynarmic_cp15.cpp
index 92c548db0..f3eee0d42 100644
--- a/src/core/arm/dynarmic/dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/dynarmic_cp15.cpp
@@ -124,8 +124,8 @@ CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc
124 if (!two && opc == 0 && CRm == CoprocReg::C14) { 124 if (!two && opc == 0 && CRm == CoprocReg::C14) {
125 // CNTPCT 125 // CNTPCT
126 const auto callback = [](void* arg, u32, u32) -> u64 { 126 const auto callback = [](void* arg, u32, u32) -> u64 {
127 const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg); 127 const auto& parent_arg = *static_cast<ArmDynarmic32*>(arg);
128 return parent_arg.system.CoreTiming().GetClockTicks(); 128 return parent_arg.m_system.CoreTiming().GetClockTicks();
129 }; 129 };
130 return Callback{callback, &parent}; 130 return Callback{callback, &parent};
131 } 131 }
diff --git a/src/core/arm/dynarmic/dynarmic_cp15.h b/src/core/arm/dynarmic/dynarmic_cp15.h
index d90b3e568..f3d96b0d8 100644
--- a/src/core/arm/dynarmic/dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/dynarmic_cp15.h
@@ -10,13 +10,13 @@
10 10
11namespace Core { 11namespace Core {
12 12
13class ARM_Dynarmic_32; 13class ArmDynarmic32;
14 14
15class DynarmicCP15 final : public Dynarmic::A32::Coprocessor { 15class DynarmicCP15 final : public Dynarmic::A32::Coprocessor {
16public: 16public:
17 using CoprocReg = Dynarmic::A32::CoprocReg; 17 using CoprocReg = Dynarmic::A32::CoprocReg;
18 18
19 explicit DynarmicCP15(ARM_Dynarmic_32& parent_) : parent{parent_} {} 19 explicit DynarmicCP15(ArmDynarmic32& parent_) : parent{parent_} {}
20 20
21 std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, 21 std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd,
22 CoprocReg CRn, CoprocReg CRm, 22 CoprocReg CRn, CoprocReg CRm,
@@ -32,11 +32,11 @@ public:
32 std::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, 32 std::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd,
33 std::optional<u8> option) override; 33 std::optional<u8> option) override;
34 34
35 ARM_Dynarmic_32& parent; 35 ArmDynarmic32& parent;
36 u32 uprw = 0; 36 u32 uprw = 0;
37 u32 uro = 0; 37 u32 uro = 0;
38 38
39 friend class ARM_Dynarmic_32; 39 friend class ArmDynarmic32;
40}; 40};
41 41
42} // namespace Core 42} // namespace Core
diff --git a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
index fbfcd8d95..c4f22ec89 100644
--- a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
+++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h
@@ -14,8 +14,8 @@ class Memory;
14 14
15namespace Core { 15namespace Core {
16 16
17class ARM_Dynarmic_32; 17class ArmDynarmic32;
18class ARM_Dynarmic_64; 18class ArmDynarmic64;
19 19
20class DynarmicExclusiveMonitor final : public ExclusiveMonitor { 20class DynarmicExclusiveMonitor final : public ExclusiveMonitor {
21public: 21public:
@@ -36,8 +36,8 @@ public:
36 bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override; 36 bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override;
37 37
38private: 38private:
39 friend class ARM_Dynarmic_32; 39 friend class ArmDynarmic32;
40 friend class ARM_Dynarmic_64; 40 friend class ArmDynarmic64;
41 Dynarmic::ExclusiveMonitor monitor; 41 Dynarmic::ExclusiveMonitor monitor;
42 Core::Memory::Memory& memory; 42 Core::Memory::Memory& memory;
43}; 43};
diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp
index f7bdafd39..b42a32a0b 100644
--- a/src/core/arm/nce/arm_nce.cpp
+++ b/src/core/arm/nce/arm_nce.cpp
@@ -6,6 +6,7 @@
6 6
7#include "common/signal_chain.h" 7#include "common/signal_chain.h"
8#include "core/arm/nce/arm_nce.h" 8#include "core/arm/nce/arm_nce.h"
9#include "core/arm/nce/guest_context.h"
9#include "core/arm/nce/patcher.h" 10#include "core/arm/nce/patcher.h"
10#include "core/core.h" 11#include "core/core.h"
11#include "core/memory.h" 12#include "core/memory.h"
@@ -38,7 +39,7 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
38 39
39} // namespace 40} // namespace
40 41
41void* ARM_NCE::RestoreGuestContext(void* raw_context) { 42void* ArmNce::RestoreGuestContext(void* raw_context) {
42 // Retrieve the host context. 43 // Retrieve the host context.
43 auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext; 44 auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
44 45
@@ -71,7 +72,7 @@ void* ARM_NCE::RestoreGuestContext(void* raw_context) {
71 return tpidr; 72 return tpidr;
72} 73}
73 74
74void ARM_NCE::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) { 75void ArmNce::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) {
75 // Retrieve the host context. 76 // Retrieve the host context.
76 auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext; 77 auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
77 78
@@ -103,7 +104,7 @@ void ARM_NCE::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) {
103 host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0); 104 host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0);
104} 105}
105 106
106bool ARM_NCE::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { 107bool ArmNce::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
107 auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext; 108 auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext;
108 auto* info = static_cast<siginfo_t*>(raw_info); 109 auto* info = static_cast<siginfo_t*>(raw_info);
109 110
@@ -134,7 +135,7 @@ bool ARM_NCE::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* ra
134 // - If we lose the race, then SignalInterrupt will send us a signal we are masking, 135 // - If we lose the race, then SignalInterrupt will send us a signal we are masking,
135 // and it will do nothing when it is unmasked, as we have already left guest code. 136 // and it will do nothing when it is unmasked, as we have already left guest code.
136 // - If we win the race, then SignalInterrupt will wait for us to unlock first. 137 // - If we win the race, then SignalInterrupt will wait for us to unlock first.
137 auto& thread_params = guest_ctx->parent->running_thread->GetNativeExecutionParameters(); 138 auto& thread_params = guest_ctx->parent->m_running_thread->GetNativeExecutionParameters();
138 thread_params.lock.store(SpinLockLocked); 139 thread_params.lock.store(SpinLockLocked);
139 140
140 // Return to host. 141 // Return to host.
@@ -142,97 +143,93 @@ bool ARM_NCE::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* ra
142 return false; 143 return false;
143} 144}
144 145
145void ARM_NCE::HandleHostFault(int sig, void* raw_info, void* raw_context) { 146void ArmNce::HandleHostFault(int sig, void* raw_info, void* raw_context) {
146 return g_orig_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context); 147 return g_orig_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context);
147} 148}
148 149
149HaltReason ARM_NCE::RunJit() { 150void ArmNce::LockThread(Kernel::KThread* thread) {
150 // Get the thread parameters.
151 // TODO: pass the current thread down from ::Run
152 auto* thread = Kernel::GetCurrentThreadPointer(system.Kernel());
153 auto* thread_params = &thread->GetNativeExecutionParameters(); 151 auto* thread_params = &thread->GetNativeExecutionParameters();
152 LockThreadParameters(thread_params);
153}
154 154
155 { 155void ArmNce::UnlockThread(Kernel::KThread* thread) {
156 // Lock our core context. 156 auto* thread_params = &thread->GetNativeExecutionParameters();
157 std::scoped_lock lk{lock}; 157 UnlockThreadParameters(thread_params);
158 158}
159 // We should not be running.
160 ASSERT(running_thread == nullptr);
161
162 // Check if we need to run. If we have already been halted, we are done.
163 u64 halt = guest_ctx.esr_el1.exchange(0);
164 if (halt != 0) {
165 return static_cast<HaltReason>(halt);
166 }
167
168 // Mark that we are running.
169 running_thread = thread;
170 159
171 // Acquire the lock on the thread parameters. 160HaltReason ArmNce::RunThread(Kernel::KThread* thread) {
172 // This allows us to force synchronization with SignalInterrupt. 161 // Check if we're already interrupted.
173 LockThreadParameters(thread_params); 162 // If we are, we can just return immediately.
163 HaltReason hr = static_cast<HaltReason>(m_guest_ctx.esr_el1.exchange(0));
164 if (True(hr)) {
165 return hr;
174 } 166 }
175 167
168 // Get the thread context.
169 auto* thread_params = &thread->GetNativeExecutionParameters();
170 auto* process = thread->GetOwnerProcess();
171
176 // Assign current members. 172 // Assign current members.
177 guest_ctx.parent = this; 173 m_running_thread = thread;
178 thread_params->native_context = &guest_ctx; 174 m_guest_ctx.parent = this;
179 thread_params->tpidr_el0 = guest_ctx.tpidr_el0; 175 thread_params->native_context = &m_guest_ctx;
180 thread_params->tpidrro_el0 = guest_ctx.tpidrro_el0; 176 thread_params->tpidr_el0 = m_guest_ctx.tpidr_el0;
177 thread_params->tpidrro_el0 = m_guest_ctx.tpidrro_el0;
181 thread_params->is_running = true; 178 thread_params->is_running = true;
182 179
183 HaltReason halt{};
184
185 // TODO: finding and creating the post handler needs to be locked 180 // TODO: finding and creating the post handler needs to be locked
186 // to deal with dynamic loading of NROs. 181 // to deal with dynamic loading of NROs.
187 const auto& post_handlers = system.ApplicationProcess()->GetPostHandlers(); 182 const auto& post_handlers = process->GetPostHandlers();
188 if (auto it = post_handlers.find(guest_ctx.pc); it != post_handlers.end()) { 183 if (auto it = post_handlers.find(m_guest_ctx.pc); it != post_handlers.end()) {
189 halt = ReturnToRunCodeByTrampoline(thread_params, &guest_ctx, it->second); 184 hr = ReturnToRunCodeByTrampoline(thread_params, &m_guest_ctx, it->second);
190 } else { 185 } else {
191 halt = ReturnToRunCodeByExceptionLevelChange(thread_id, thread_params); 186 hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params);
192 } 187 }
193 188
194 // Unload members. 189 // Unload members.
195 // The thread does not change, so we can persist the old reference. 190 // The thread does not change, so we can persist the old reference.
196 guest_ctx.tpidr_el0 = thread_params->tpidr_el0; 191 m_running_thread = nullptr;
192 m_guest_ctx.tpidr_el0 = thread_params->tpidr_el0;
197 thread_params->native_context = nullptr; 193 thread_params->native_context = nullptr;
198 thread_params->is_running = false; 194 thread_params->is_running = false;
199 195
200 // Unlock the thread parameters.
201 UnlockThreadParameters(thread_params);
202
203 {
204 // Lock the core context.
205 std::scoped_lock lk{lock};
206
207 // On exit, we no longer have an active thread.
208 running_thread = nullptr;
209 }
210
211 // Return the halt reason. 196 // Return the halt reason.
212 return halt; 197 return hr;
213} 198}
214 199
215HaltReason ARM_NCE::StepJit() { 200HaltReason ArmNce::StepThread(Kernel::KThread* thread) {
216 return HaltReason::StepThread; 201 return HaltReason::StepThread;
217} 202}
218 203
219u32 ARM_NCE::GetSvcNumber() const { 204u32 ArmNce::GetSvcNumber() const {
220 return guest_ctx.svc_swi; 205 return m_guest_ctx.svc;
206}
207
208void ArmNce::GetSvcArguments(std::span<uint64_t, 8> args) const {
209 for (size_t i = 0; i < 8; i++) {
210 args[i] = m_guest_ctx.cpu_registers[i];
211 }
212}
213
214void ArmNce::SetSvcArguments(std::span<const uint64_t, 8> args) {
215 for (size_t i = 0; i < 8; i++) {
216 m_guest_ctx.cpu_registers[i] = args[i];
217 }
221} 218}
222 219
223ARM_NCE::ARM_NCE(System& system_, bool uses_wall_clock_, std::size_t core_index_) 220ArmNce::ArmNce(System& system, bool uses_wall_clock, std::size_t core_index)
224 : ARM_Interface{system_, uses_wall_clock_}, core_index{core_index_} { 221 : ArmInterface{uses_wall_clock}, m_system{system}, m_core_index{core_index} {
225 guest_ctx.system = &system_; 222 m_guest_ctx.system = &m_system;
226} 223}
227 224
228ARM_NCE::~ARM_NCE() = default; 225ArmNce::~ArmNce() = default;
229 226
230void ARM_NCE::Initialize() { 227void ArmNce::Initialize() {
231 thread_id = gettid(); 228 m_thread_id = gettid();
232 229
233 // Setup our signals 230 // Setup our signals
234 static std::once_flag flag; 231 static std::once_flag signals;
235 std::call_once(flag, [] { 232 std::call_once(signals, [] {
236 using HandlerType = decltype(sigaction::sa_sigaction); 233 using HandlerType = decltype(sigaction::sa_sigaction);
237 234
238 sigset_t signal_mask; 235 sigset_t signal_mask;
@@ -244,7 +241,7 @@ void ARM_NCE::Initialize() {
244 struct sigaction return_to_run_code_action {}; 241 struct sigaction return_to_run_code_action {};
245 return_to_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK; 242 return_to_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
246 return_to_run_code_action.sa_sigaction = reinterpret_cast<HandlerType>( 243 return_to_run_code_action.sa_sigaction = reinterpret_cast<HandlerType>(
247 &ARM_NCE::ReturnToRunCodeByExceptionLevelChangeSignalHandler); 244 &ArmNce::ReturnToRunCodeByExceptionLevelChangeSignalHandler);
248 return_to_run_code_action.sa_mask = signal_mask; 245 return_to_run_code_action.sa_mask = signal_mask;
249 Common::SigAction(ReturnToRunCodeByExceptionLevelChangeSignal, &return_to_run_code_action, 246 Common::SigAction(ReturnToRunCodeByExceptionLevelChangeSignal, &return_to_run_code_action,
250 nullptr); 247 nullptr);
@@ -252,14 +249,13 @@ void ARM_NCE::Initialize() {
252 struct sigaction break_from_run_code_action {}; 249 struct sigaction break_from_run_code_action {};
253 break_from_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK; 250 break_from_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
254 break_from_run_code_action.sa_sigaction = 251 break_from_run_code_action.sa_sigaction =
255 reinterpret_cast<HandlerType>(&ARM_NCE::BreakFromRunCodeSignalHandler); 252 reinterpret_cast<HandlerType>(&ArmNce::BreakFromRunCodeSignalHandler);
256 break_from_run_code_action.sa_mask = signal_mask; 253 break_from_run_code_action.sa_mask = signal_mask;
257 Common::SigAction(BreakFromRunCodeSignal, &break_from_run_code_action, nullptr); 254 Common::SigAction(BreakFromRunCodeSignal, &break_from_run_code_action, nullptr);
258 255
259 struct sigaction fault_action {}; 256 struct sigaction fault_action {};
260 fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART; 257 fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
261 fault_action.sa_sigaction = 258 fault_action.sa_sigaction = reinterpret_cast<HandlerType>(&ArmNce::GuestFaultSignalHandler);
262 reinterpret_cast<HandlerType>(&ARM_NCE::GuestFaultSignalHandler);
263 fault_action.sa_mask = signal_mask; 259 fault_action.sa_mask = signal_mask;
264 Common::SigAction(GuestFaultSignal, &fault_action, &g_orig_action); 260 Common::SigAction(GuestFaultSignal, &fault_action, &g_orig_action);
265 261
@@ -272,111 +268,59 @@ void ARM_NCE::Initialize() {
272 }); 268 });
273} 269}
274 270
275void ARM_NCE::SetPC(u64 pc) { 271void ArmNce::SetTpidrroEl0(u64 value) {
276 guest_ctx.pc = pc; 272 m_guest_ctx.tpidrro_el0 = value;
277} 273}
278 274
279u64 ARM_NCE::GetPC() const { 275void ArmNce::GetContext(Kernel::Svc::ThreadContext& ctx) const {
280 return guest_ctx.pc; 276 for (size_t i = 0; i < 29; i++) {
281} 277 ctx.r[i] = m_guest_ctx.cpu_registers[i];
282 278 }
283u64 ARM_NCE::GetSP() const { 279 ctx.fp = m_guest_ctx.cpu_registers[29];
284 return guest_ctx.sp; 280 ctx.lr = m_guest_ctx.cpu_registers[30];
285} 281 ctx.sp = m_guest_ctx.sp;
286 282 ctx.pc = m_guest_ctx.pc;
287u64 ARM_NCE::GetReg(int index) const { 283 ctx.pstate = m_guest_ctx.pstate;
288 return guest_ctx.cpu_registers[index]; 284 ctx.v = m_guest_ctx.vector_registers;
289} 285 ctx.fpcr = m_guest_ctx.fpcr;
290 286 ctx.fpsr = m_guest_ctx.fpsr;
291void ARM_NCE::SetReg(int index, u64 value) { 287 ctx.tpidr = m_guest_ctx.tpidr_el0;
292 guest_ctx.cpu_registers[index] = value;
293}
294
295u128 ARM_NCE::GetVectorReg(int index) const {
296 return guest_ctx.vector_registers[index];
297}
298
299void ARM_NCE::SetVectorReg(int index, u128 value) {
300 guest_ctx.vector_registers[index] = value;
301}
302
303u32 ARM_NCE::GetPSTATE() const {
304 return guest_ctx.pstate;
305}
306
307void ARM_NCE::SetPSTATE(u32 pstate) {
308 guest_ctx.pstate = pstate;
309}
310
311u64 ARM_NCE::GetTlsAddress() const {
312 return guest_ctx.tpidrro_el0;
313}
314
315void ARM_NCE::SetTlsAddress(u64 address) {
316 guest_ctx.tpidrro_el0 = address;
317}
318
319u64 ARM_NCE::GetTPIDR_EL0() const {
320 return guest_ctx.tpidr_el0;
321}
322
323void ARM_NCE::SetTPIDR_EL0(u64 value) {
324 guest_ctx.tpidr_el0 = value;
325}
326
327void ARM_NCE::SaveContext(ThreadContext64& ctx) const {
328 ctx.cpu_registers = guest_ctx.cpu_registers;
329 ctx.sp = guest_ctx.sp;
330 ctx.pc = guest_ctx.pc;
331 ctx.pstate = guest_ctx.pstate;
332 ctx.vector_registers = guest_ctx.vector_registers;
333 ctx.fpcr = guest_ctx.fpcr;
334 ctx.fpsr = guest_ctx.fpsr;
335 ctx.tpidr = guest_ctx.tpidr_el0;
336} 288}
337 289
338void ARM_NCE::LoadContext(const ThreadContext64& ctx) { 290void ArmNce::SetContext(const Kernel::Svc::ThreadContext& ctx) {
339 guest_ctx.cpu_registers = ctx.cpu_registers; 291 for (size_t i = 0; i < 29; i++) {
340 guest_ctx.sp = ctx.sp; 292 m_guest_ctx.cpu_registers[i] = ctx.r[i];
341 guest_ctx.pc = ctx.pc; 293 }
342 guest_ctx.pstate = ctx.pstate; 294 m_guest_ctx.cpu_registers[29] = ctx.fp;
343 guest_ctx.vector_registers = ctx.vector_registers; 295 m_guest_ctx.cpu_registers[30] = ctx.lr;
344 guest_ctx.fpcr = ctx.fpcr; 296 m_guest_ctx.sp = ctx.sp;
345 guest_ctx.fpsr = ctx.fpsr; 297 m_guest_ctx.pc = ctx.pc;
346 guest_ctx.tpidr_el0 = ctx.tpidr; 298 m_guest_ctx.pstate = ctx.pstate;
299 m_guest_ctx.vector_registers = ctx.v;
300 m_guest_ctx.fpcr = ctx.fpcr;
301 m_guest_ctx.fpsr = ctx.fpsr;
302 m_guest_ctx.tpidr_el0 = ctx.tpidr;
347} 303}
348 304
349void ARM_NCE::SignalInterrupt() { 305void ArmNce::SignalInterrupt(Kernel::KThread* thread) {
350 // Lock core context.
351 std::scoped_lock lk{lock};
352
353 // Add break loop condition. 306 // Add break loop condition.
354 guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop)); 307 m_guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop));
355
356 // If there is no thread running, we are done.
357 if (running_thread == nullptr) {
358 return;
359 }
360 308
361 // Lock the thread context. 309 // Lock the thread context.
362 auto* params = &running_thread->GetNativeExecutionParameters(); 310 auto* params = &thread->GetNativeExecutionParameters();
363 LockThreadParameters(params); 311 LockThreadParameters(params);
364 312
365 if (params->is_running) { 313 if (params->is_running) {
366 // We should signal to the running thread. 314 // We should signal to the running thread.
367 // The running thread will unlock the thread context. 315 // The running thread will unlock the thread context.
368 syscall(SYS_tkill, thread_id, BreakFromRunCodeSignal); 316 syscall(SYS_tkill, m_thread_id, BreakFromRunCodeSignal);
369 } else { 317 } else {
370 // If the thread is no longer running, we have nothing to do. 318 // If the thread is no longer running, we have nothing to do.
371 UnlockThreadParameters(params); 319 UnlockThreadParameters(params);
372 } 320 }
373} 321}
374 322
375void ARM_NCE::ClearInterrupt() { 323void ArmNce::ClearInstructionCache() {
376 guest_ctx.esr_el1 = {};
377}
378
379void ARM_NCE::ClearInstructionCache() {
380 // TODO: This is not possible to implement correctly on Linux because 324 // TODO: This is not possible to implement correctly on Linux because
381 // we do not have any access to ic iallu. 325 // we do not have any access to ic iallu.
382 326
@@ -384,17 +328,8 @@ void ARM_NCE::ClearInstructionCache() {
384 std::atomic_thread_fence(std::memory_order_seq_cst); 328 std::atomic_thread_fence(std::memory_order_seq_cst);
385} 329}
386 330
387void ARM_NCE::InvalidateCacheRange(u64 addr, std::size_t size) { 331void ArmNce::InvalidateCacheRange(u64 addr, std::size_t size) {
388 this->ClearInstructionCache(); 332 this->ClearInstructionCache();
389} 333}
390 334
391void ARM_NCE::ClearExclusiveState() {
392 // No-op.
393}
394
395void ARM_NCE::PageTableChanged(Common::PageTable& page_table,
396 std::size_t new_address_space_size_in_bits) {
397 // No-op. Page table is never used.
398}
399
400} // namespace Core 335} // namespace Core
diff --git a/src/core/arm/nce/arm_nce.h b/src/core/arm/nce/arm_nce.h
index 5fbd6dbf3..f55c10d1d 100644
--- a/src/core/arm/nce/arm_nce.h
+++ b/src/core/arm/nce/arm_nce.h
@@ -3,11 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <atomic> 6#include <mutex>
7#include <memory>
8#include <span>
9#include <unordered_map>
10#include <vector>
11 7
12#include "core/arm/arm_interface.h" 8#include "core/arm/arm_interface.h"
13#include "core/arm/nce/guest_context.h" 9#include "core/arm/nce/guest_context.h"
@@ -20,51 +16,36 @@ namespace Core {
20 16
21class System; 17class System;
22 18
23class ARM_NCE final : public ARM_Interface { 19class ArmNce final : public ArmInterface {
24public: 20public:
25 ARM_NCE(System& system_, bool uses_wall_clock_, std::size_t core_index_); 21 ArmNce(System& system, bool uses_wall_clock, std::size_t core_index);
26 22 ~ArmNce() override;
27 ~ARM_NCE() override;
28 23
29 void Initialize() override; 24 void Initialize() override;
30 void SetPC(u64 pc) override;
31 u64 GetPC() const override;
32 u64 GetSP() const override;
33 u64 GetReg(int index) const override;
34 void SetReg(int index, u64 value) override;
35 u128 GetVectorReg(int index) const override;
36 void SetVectorReg(int index, u128 value) override;
37
38 u32 GetPSTATE() const override;
39 void SetPSTATE(u32 pstate) override;
40 u64 GetTlsAddress() const override;
41 void SetTlsAddress(u64 address) override;
42 void SetTPIDR_EL0(u64 value) override;
43 u64 GetTPIDR_EL0() const override;
44 25
45 Architecture GetArchitecture() const override { 26 Architecture GetArchitecture() const override {
46 return Architecture::Aarch64; 27 return Architecture::AArch64;
47 } 28 }
48 29
49 void SaveContext(ThreadContext32& ctx) const override {} 30 HaltReason RunThread(Kernel::KThread* thread) override;
50 void SaveContext(ThreadContext64& ctx) const override; 31 HaltReason StepThread(Kernel::KThread* thread) override;
51 void LoadContext(const ThreadContext32& ctx) override {} 32
52 void LoadContext(const ThreadContext64& ctx) override; 33 void GetContext(Kernel::Svc::ThreadContext& ctx) const override;
34 void SetContext(const Kernel::Svc::ThreadContext& ctx) override;
35 void SetTpidrroEl0(u64 value) override;
53 36
54 void SignalInterrupt() override; 37 void GetSvcArguments(std::span<uint64_t, 8> args) const override;
55 void ClearInterrupt() override; 38 void SetSvcArguments(std::span<const uint64_t, 8> args) override;
56 void ClearExclusiveState() override; 39 u32 GetSvcNumber() const override;
40
41 void SignalInterrupt(Kernel::KThread* thread) override;
57 void ClearInstructionCache() override; 42 void ClearInstructionCache() override;
58 void InvalidateCacheRange(u64 addr, std::size_t size) override; 43 void InvalidateCacheRange(u64 addr, std::size_t size) override;
59 void PageTableChanged(Common::PageTable& new_page_table,
60 std::size_t new_address_space_size_in_bits) override;
61
62protected:
63 HaltReason RunJit() override;
64 HaltReason StepJit() override;
65 44
66 u32 GetSvcNumber() const override; 45 void LockThread(Kernel::KThread* thread) override;
46 void UnlockThread(Kernel::KThread* thread) override;
67 47
48protected:
68 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override { 49 const Kernel::DebugWatchpoint* HaltedWatchpoint() const override {
69 return nullptr; 50 return nullptr;
70 } 51 }
@@ -93,16 +74,15 @@ private:
93 static void HandleHostFault(int sig, void* info, void* raw_context); 74 static void HandleHostFault(int sig, void* info, void* raw_context);
94 75
95public: 76public:
77 Core::System& m_system;
78
96 // Members set on initialization. 79 // Members set on initialization.
97 std::size_t core_index{}; 80 std::size_t m_core_index{};
98 pid_t thread_id{-1}; 81 pid_t m_thread_id{-1};
99 82
100 // Core context. 83 // Core context.
101 GuestContext guest_ctx; 84 GuestContext m_guest_ctx{};
102 85 Kernel::KThread* m_running_thread{};
103 // Thread and invalidation info.
104 std::mutex lock;
105 Kernel::KThread* running_thread{};
106}; 86};
107 87
108} // namespace Core 88} // namespace Core
diff --git a/src/core/arm/nce/arm_nce.s b/src/core/arm/nce/arm_nce.s
index b98e09f31..4aeda4740 100644
--- a/src/core/arm/nce/arm_nce.s
+++ b/src/core/arm/nce/arm_nce.s
@@ -8,11 +8,11 @@
8 movk reg, #(((val) >> 0x10) & 0xFFFF), lsl #16 8 movk reg, #(((val) >> 0x10) & 0xFFFF), lsl #16
9 9
10 10
11/* static HaltReason Core::ARM_NCE::ReturnToRunCodeByTrampoline(void* tpidr, Core::GuestContext* ctx, u64 trampoline_addr) */ 11/* static HaltReason Core::ArmNce::ReturnToRunCodeByTrampoline(void* tpidr, Core::GuestContext* ctx, u64 trampoline_addr) */
12.section .text._ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, "ax", %progbits 12.section .text._ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, "ax", %progbits
13.global _ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm 13.global _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm
14.type _ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, %function 14.type _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, %function
15_ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm: 15_ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm:
16 /* Back up host sp to x3. */ 16 /* Back up host sp to x3. */
17 /* Back up host tpidr_el0 to x4. */ 17 /* Back up host tpidr_el0 to x4. */
18 mov x3, sp 18 mov x3, sp
@@ -49,11 +49,11 @@ _ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm:
49 br x2 49 br x2
50 50
51 51
52/* static HaltReason Core::ARM_NCE::ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr) */ 52/* static HaltReason Core::ArmNce::ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr) */
53.section .text._ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv, "ax", %progbits 53.section .text._ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv, "ax", %progbits
54.global _ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv 54.global _ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv
55.type _ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv, %function 55.type _ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv, %function
56_ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv: 56_ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv:
57 /* This jumps to the signal handler, which will restore the entire context. */ 57 /* This jumps to the signal handler, which will restore the entire context. */
58 /* On entry, x0 = thread id, which is already in the right place. */ 58 /* On entry, x0 = thread id, which is already in the right place. */
59 59
@@ -71,17 +71,17 @@ _ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv:
71 brk #1000 71 brk #1000
72 72
73 73
74/* static void Core::ARM_NCE::ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info, void* raw_context) */ 74/* static void Core::ArmNce::ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info, void* raw_context) */
75.section .text._ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, "ax", %progbits 75.section .text._ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, "ax", %progbits
76.global _ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_ 76.global _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_
77.type _ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, %function 77.type _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, %function
78_ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_: 78_ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_:
79 stp x29, x30, [sp, #-0x10]! 79 stp x29, x30, [sp, #-0x10]!
80 mov x29, sp 80 mov x29, sp
81 81
82 /* Call the context restorer with the raw context. */ 82 /* Call the context restorer with the raw context. */
83 mov x0, x2 83 mov x0, x2
84 bl _ZN4Core7ARM_NCE19RestoreGuestContextEPv 84 bl _ZN4Core6ArmNce19RestoreGuestContextEPv
85 85
86 /* Save the old value of tpidr_el0. */ 86 /* Save the old value of tpidr_el0. */
87 mrs x8, tpidr_el0 87 mrs x8, tpidr_el0
@@ -92,18 +92,18 @@ _ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_:
92 msr tpidr_el0, x0 92 msr tpidr_el0, x0
93 93
94 /* Unlock the context. */ 94 /* Unlock the context. */
95 bl _ZN4Core7ARM_NCE22UnlockThreadParametersEPv 95 bl _ZN4Core6ArmNce22UnlockThreadParametersEPv
96 96
97 /* Returning from here will enter the guest. */ 97 /* Returning from here will enter the guest. */
98 ldp x29, x30, [sp], #0x10 98 ldp x29, x30, [sp], #0x10
99 ret 99 ret
100 100
101 101
102/* static void Core::ARM_NCE::BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context) */ 102/* static void Core::ArmNce::BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context) */
103.section .text._ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_, "ax", %progbits 103.section .text._ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_, "ax", %progbits
104.global _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_ 104.global _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_
105.type _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_, %function 105.type _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_, %function
106_ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_: 106_ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_:
107 /* Check to see if we have the correct TLS magic. */ 107 /* Check to see if we have the correct TLS magic. */
108 mrs x8, tpidr_el0 108 mrs x8, tpidr_el0
109 ldr w9, [x8, #(TpidrEl0TlsMagic)] 109 ldr w9, [x8, #(TpidrEl0TlsMagic)]
@@ -121,7 +121,7 @@ _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_:
121 121
122 /* Tail call the restorer. */ 122 /* Tail call the restorer. */
123 mov x1, x2 123 mov x1, x2
124 b _ZN4Core7ARM_NCE16SaveGuestContextEPNS_12GuestContextEPv 124 b _ZN4Core6ArmNce16SaveGuestContextEPNS_12GuestContextEPv
125 125
126 /* Returning from here will enter host code. */ 126 /* Returning from here will enter host code. */
127 127
@@ -130,11 +130,11 @@ _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_:
130 ret 130 ret
131 131
132 132
133/* static void Core::ARM_NCE::GuestFaultSignalHandler(int sig, void* info, void* raw_context) */ 133/* static void Core::ArmNce::GuestFaultSignalHandler(int sig, void* info, void* raw_context) */
134.section .text._ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_, "ax", %progbits 134.section .text._ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, "ax", %progbits
135.global _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_ 135.global _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_
136.type _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_, %function 136.type _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, %function
137_ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_: 137_ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_:
138 /* Check to see if we have the correct TLS magic. */ 138 /* Check to see if we have the correct TLS magic. */
139 mrs x8, tpidr_el0 139 mrs x8, tpidr_el0
140 ldr w9, [x8, #(TpidrEl0TlsMagic)] 140 ldr w9, [x8, #(TpidrEl0TlsMagic)]
@@ -146,7 +146,7 @@ _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_:
146 146
147 /* Incorrect TLS magic, so this is a host fault. */ 147 /* Incorrect TLS magic, so this is a host fault. */
148 /* Tail call the handler. */ 148 /* Tail call the handler. */
149 b _ZN4Core7ARM_NCE15HandleHostFaultEiPvS1_ 149 b _ZN4Core6ArmNce15HandleHostFaultEiPvS1_
150 150
1511: 1511:
152 /* Correct TLS magic, so this is a guest fault. */ 152 /* Correct TLS magic, so this is a guest fault. */
@@ -163,7 +163,7 @@ _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_:
163 msr tpidr_el0, x3 163 msr tpidr_el0, x3
164 164
165 /* Call the handler. */ 165 /* Call the handler. */
166 bl _ZN4Core7ARM_NCE16HandleGuestFaultEPNS_12GuestContextEPvS3_ 166 bl _ZN4Core6ArmNce16HandleGuestFaultEPNS_12GuestContextEPvS3_
167 167
168 /* If the handler returned false, we want to preserve the host tpidr_el0. */ 168 /* If the handler returned false, we want to preserve the host tpidr_el0. */
169 cbz x0, 2f 169 cbz x0, 2f
@@ -177,11 +177,11 @@ _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_:
177 ret 177 ret
178 178
179 179
180/* static void Core::ARM_NCE::LockThreadParameters(void* tpidr) */ 180/* static void Core::ArmNce::LockThreadParameters(void* tpidr) */
181.section .text._ZN4Core7ARM_NCE20LockThreadParametersEPv, "ax", %progbits 181.section .text._ZN4Core6ArmNce20LockThreadParametersEPv, "ax", %progbits
182.global _ZN4Core7ARM_NCE20LockThreadParametersEPv 182.global _ZN4Core6ArmNce20LockThreadParametersEPv
183.type _ZN4Core7ARM_NCE20LockThreadParametersEPv, %function 183.type _ZN4Core6ArmNce20LockThreadParametersEPv, %function
184_ZN4Core7ARM_NCE20LockThreadParametersEPv: 184_ZN4Core6ArmNce20LockThreadParametersEPv:
185 /* Offset to lock member. */ 185 /* Offset to lock member. */
186 add x0, x0, #(TpidrEl0Lock) 186 add x0, x0, #(TpidrEl0Lock)
187 187
@@ -205,11 +205,11 @@ _ZN4Core7ARM_NCE20LockThreadParametersEPv:
205 ret 205 ret
206 206
207 207
208/* static void Core::ARM_NCE::UnlockThreadParameters(void* tpidr) */ 208/* static void Core::ArmNce::UnlockThreadParameters(void* tpidr) */
209.section .text._ZN4Core7ARM_NCE22UnlockThreadParametersEPv, "ax", %progbits 209.section .text._ZN4Core6ArmNce22UnlockThreadParametersEPv, "ax", %progbits
210.global _ZN4Core7ARM_NCE22UnlockThreadParametersEPv 210.global _ZN4Core6ArmNce22UnlockThreadParametersEPv
211.type _ZN4Core7ARM_NCE22UnlockThreadParametersEPv, %function 211.type _ZN4Core6ArmNce22UnlockThreadParametersEPv, %function
212_ZN4Core7ARM_NCE22UnlockThreadParametersEPv: 212_ZN4Core6ArmNce22UnlockThreadParametersEPv:
213 /* Offset to lock member. */ 213 /* Offset to lock member. */
214 add x0, x0, #(TpidrEl0Lock) 214 add x0, x0, #(TpidrEl0Lock)
215 215
diff --git a/src/core/arm/nce/guest_context.h b/src/core/arm/nce/guest_context.h
index 0767a0337..a7eadccce 100644
--- a/src/core/arm/nce/guest_context.h
+++ b/src/core/arm/nce/guest_context.h
@@ -3,6 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <atomic>
7
6#include "common/common_funcs.h" 8#include "common/common_funcs.h"
7#include "common/common_types.h" 9#include "common/common_types.h"
8#include "core/arm/arm_interface.h" 10#include "core/arm/arm_interface.h"
@@ -10,7 +12,7 @@
10 12
11namespace Core { 13namespace Core {
12 14
13class ARM_NCE; 15class ArmNce;
14class System; 16class System;
15 17
16struct HostContext { 18struct HostContext {
@@ -33,9 +35,9 @@ struct GuestContext {
33 u64 tpidr_el0{}; 35 u64 tpidr_el0{};
34 std::atomic<u64> esr_el1{}; 36 std::atomic<u64> esr_el1{};
35 u32 nzcv{}; 37 u32 nzcv{};
36 u32 svc_swi{}; 38 u32 svc{};
37 System* system{}; 39 System* system{};
38 ARM_NCE* parent{}; 40 ArmNce* parent{};
39}; 41};
40 42
41// Verify assembly offsets. 43// Verify assembly offsets.
diff --git a/src/core/arm/nce/patcher.cpp b/src/core/arm/nce/patcher.cpp
index bdaa3af49..47a7a8880 100644
--- a/src/core/arm/nce/patcher.cpp
+++ b/src/core/arm/nce/patcher.cpp
@@ -280,7 +280,7 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id) {
280 280
281 // Store SVC number to execute when we return 281 // Store SVC number to execute when we return
282 c.MOV(X2, svc_id); 282 c.MOV(X2, svc_id);
283 c.STR(W2, X1, offsetof(GuestContext, svc_swi)); 283 c.STR(W2, X1, offsetof(GuestContext, svc));
284 284
285 // We are calling a SVC. Clear esr_el1 and return it. 285 // We are calling a SVC. Clear esr_el1 and return it.
286 static_assert(std::is_same_v<std::underlying_type_t<HaltReason>, u64>); 286 static_assert(std::is_same_v<std::underlying_type_t<HaltReason>, u64>);
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 14d6c8c27..b14f74976 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -36,6 +36,7 @@
36#include "core/hle/kernel/k_scheduler.h" 36#include "core/hle/kernel/k_scheduler.h"
37#include "core/hle/kernel/kernel.h" 37#include "core/hle/kernel/kernel.h"
38#include "core/hle/kernel/physical_core.h" 38#include "core/hle/kernel/physical_core.h"
39#include "core/hle/service/acc/profile_manager.h"
39#include "core/hle/service/am/applets/applets.h" 40#include "core/hle/service/am/applets/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"
@@ -130,8 +131,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
130struct System::Impl { 131struct System::Impl {
131 explicit Impl(System& system) 132 explicit Impl(System& system)
132 : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{}, 133 : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{},
133 cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system}, 134 cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{},
134 gpu_dirty_memory_write_manager{} { 135 time_manager{system}, gpu_dirty_memory_write_manager{} {
135 memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager); 136 memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
136 } 137 }
137 138
@@ -323,7 +324,6 @@ struct System::Impl {
323 static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); 324 static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
324 } 325 }
325 AddGlueRegistrationForProcess(*app_loader, *main_process); 326 AddGlueRegistrationForProcess(*app_loader, *main_process);
326 kernel.InitializeCores();
327 327
328 // Initialize cheat engine 328 // Initialize cheat engine
329 if (cheat_engine) { 329 if (cheat_engine) {
@@ -533,6 +533,7 @@ struct System::Impl {
533 533
534 /// Service State 534 /// Service State
535 Service::Glue::ARPManager arp_manager; 535 Service::Glue::ARPManager arp_manager;
536 Service::Account::ProfileManager profile_manager;
536 Service::Time::TimeManager time_manager; 537 Service::Time::TimeManager time_manager;
537 538
538 /// Service manager 539 /// Service manager
@@ -600,14 +601,6 @@ bool System::IsPaused() const {
600 return impl->IsPaused(); 601 return impl->IsPaused();
601} 602}
602 603
603void System::InvalidateCpuInstructionCaches() {
604 impl->kernel.InvalidateAllInstructionCaches();
605}
606
607void System::InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size) {
608 impl->kernel.InvalidateCpuInstructionCacheRange(addr, size);
609}
610
611void System::ShutdownMainProcess() { 604void System::ShutdownMainProcess() {
612 impl->ShutdownMainProcess(); 605 impl->ShutdownMainProcess();
613} 606}
@@ -696,14 +689,6 @@ const TelemetrySession& System::TelemetrySession() const {
696 return *impl->telemetry_session; 689 return *impl->telemetry_session;
697} 690}
698 691
699ARM_Interface& System::CurrentArmInterface() {
700 return impl->kernel.CurrentPhysicalCore().ArmInterface();
701}
702
703const ARM_Interface& System::CurrentArmInterface() const {
704 return impl->kernel.CurrentPhysicalCore().ArmInterface();
705}
706
707Kernel::PhysicalCore& System::CurrentPhysicalCore() { 692Kernel::PhysicalCore& System::CurrentPhysicalCore() {
708 return impl->kernel.CurrentPhysicalCore(); 693 return impl->kernel.CurrentPhysicalCore();
709} 694}
@@ -738,14 +723,6 @@ const Kernel::KProcess* System::ApplicationProcess() const {
738 return impl->kernel.ApplicationProcess(); 723 return impl->kernel.ApplicationProcess();
739} 724}
740 725
741ARM_Interface& System::ArmInterface(std::size_t core_index) {
742 return impl->kernel.PhysicalCore(core_index).ArmInterface();
743}
744
745const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
746 return impl->kernel.PhysicalCore(core_index).ArmInterface();
747}
748
749ExclusiveMonitor& System::Monitor() { 726ExclusiveMonitor& System::Monitor() {
750 return impl->kernel.GetExclusiveMonitor(); 727 return impl->kernel.GetExclusiveMonitor();
751} 728}
@@ -946,6 +923,14 @@ const Service::APM::Controller& System::GetAPMController() const {
946 return impl->apm_controller; 923 return impl->apm_controller;
947} 924}
948 925
926Service::Account::ProfileManager& System::GetProfileManager() {
927 return impl->profile_manager;
928}
929
930const Service::Account::ProfileManager& System::GetProfileManager() const {
931 return impl->profile_manager;
932}
933
949Service::Time::TimeManager& System::GetTimeManager() { 934Service::Time::TimeManager& System::GetTimeManager() {
950 return impl->time_manager; 935 return impl->time_manager;
951} 936}
diff --git a/src/core/core.h b/src/core/core.h
index df20f26f3..473204db7 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -45,6 +45,10 @@ class Memory;
45 45
46namespace Service { 46namespace Service {
47 47
48namespace Account {
49class ProfileManager;
50} // namespace Account
51
48namespace AM::Applets { 52namespace AM::Applets {
49struct AppletFrontendSet; 53struct AppletFrontendSet;
50class AppletManager; 54class AppletManager;
@@ -108,7 +112,6 @@ class RenderdocAPI;
108 112
109namespace Core { 113namespace Core {
110 114
111class ARM_Interface;
112class CpuManager; 115class CpuManager;
113class Debugger; 116class Debugger;
114class DeviceMemory; 117class DeviceMemory;
@@ -171,15 +174,6 @@ public:
171 /// Check if the core is currently paused. 174 /// Check if the core is currently paused.
172 [[nodiscard]] bool IsPaused() const; 175 [[nodiscard]] bool IsPaused() const;
173 176
174 /**
175 * Invalidate the CPU instruction caches
176 * This function should only be used by GDB Stub to support breakpoints, memory updates and
177 * step/continue commands.
178 */
179 void InvalidateCpuInstructionCaches();
180
181 void InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size);
182
183 /// Shutdown the main emulated process. 177 /// Shutdown the main emulated process.
184 void ShutdownMainProcess(); 178 void ShutdownMainProcess();
185 179
@@ -244,24 +238,12 @@ public:
244 /// Gets and resets core performance statistics 238 /// Gets and resets core performance statistics
245 [[nodiscard]] PerfStatsResults GetAndResetPerfStats(); 239 [[nodiscard]] PerfStatsResults GetAndResetPerfStats();
246 240
247 /// Gets an ARM interface to the CPU core that is currently running
248 [[nodiscard]] ARM_Interface& CurrentArmInterface();
249
250 /// Gets an ARM interface to the CPU core that is currently running
251 [[nodiscard]] const ARM_Interface& CurrentArmInterface() const;
252
253 /// Gets the physical core for the CPU core that is currently running 241 /// Gets the physical core for the CPU core that is currently running
254 [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore(); 242 [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore();
255 243
256 /// Gets the physical core for the CPU core that is currently running 244 /// Gets the physical core for the CPU core that is currently running
257 [[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const; 245 [[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const;
258 246
259 /// Gets a reference to an ARM interface for the CPU core with the specified index
260 [[nodiscard]] ARM_Interface& ArmInterface(std::size_t core_index);
261
262 /// Gets a const reference to an ARM interface from the CPU core with the specified index
263 [[nodiscard]] const ARM_Interface& ArmInterface(std::size_t core_index) const;
264
265 /// Gets a reference to the underlying CPU manager. 247 /// Gets a reference to the underlying CPU manager.
266 [[nodiscard]] CpuManager& GetCpuManager(); 248 [[nodiscard]] CpuManager& GetCpuManager();
267 249
@@ -405,6 +387,9 @@ public:
405 [[nodiscard]] Service::APM::Controller& GetAPMController(); 387 [[nodiscard]] Service::APM::Controller& GetAPMController();
406 [[nodiscard]] const Service::APM::Controller& GetAPMController() const; 388 [[nodiscard]] const Service::APM::Controller& GetAPMController() const;
407 389
390 [[nodiscard]] Service::Account::ProfileManager& GetProfileManager();
391 [[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const;
392
408 [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); 393 [[nodiscard]] Service::Time::TimeManager& GetTimeManager();
409 [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; 394 [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
410 395
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 151eb3870..7a5c22f78 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -73,12 +73,13 @@ void CpuManager::HandleInterrupt() {
73void CpuManager::MultiCoreRunGuestThread() { 73void CpuManager::MultiCoreRunGuestThread() {
74 // Similar to UserModeThreadStarter in HOS 74 // Similar to UserModeThreadStarter in HOS
75 auto& kernel = system.Kernel(); 75 auto& kernel = system.Kernel();
76 auto* thread = Kernel::GetCurrentThreadPointer(kernel);
76 kernel.CurrentScheduler()->OnThreadStart(); 77 kernel.CurrentScheduler()->OnThreadStart();
77 78
78 while (true) { 79 while (true) {
79 auto* physical_core = &kernel.CurrentPhysicalCore(); 80 auto* physical_core = &kernel.CurrentPhysicalCore();
80 while (!physical_core->IsInterrupted()) { 81 while (!physical_core->IsInterrupted()) {
81 physical_core->Run(); 82 physical_core->RunThread(thread);
82 physical_core = &kernel.CurrentPhysicalCore(); 83 physical_core = &kernel.CurrentPhysicalCore();
83 } 84 }
84 85
@@ -110,12 +111,13 @@ void CpuManager::MultiCoreRunIdleThread() {
110 111
111void CpuManager::SingleCoreRunGuestThread() { 112void CpuManager::SingleCoreRunGuestThread() {
112 auto& kernel = system.Kernel(); 113 auto& kernel = system.Kernel();
114 auto* thread = Kernel::GetCurrentThreadPointer(kernel);
113 kernel.CurrentScheduler()->OnThreadStart(); 115 kernel.CurrentScheduler()->OnThreadStart();
114 116
115 while (true) { 117 while (true) {
116 auto* physical_core = &kernel.CurrentPhysicalCore(); 118 auto* physical_core = &kernel.CurrentPhysicalCore();
117 if (!physical_core->IsInterrupted()) { 119 if (!physical_core->IsInterrupted()) {
118 physical_core->Run(); 120 physical_core->RunThread(thread);
119 physical_core = &kernel.CurrentPhysicalCore(); 121 physical_core = &kernel.CurrentPhysicalCore();
120 } 122 }
121 123
@@ -211,8 +213,6 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) {
211 system.GPU().ObtainContext(); 213 system.GPU().ObtainContext();
212 } 214 }
213 215
214 system.ArmInterface(core).Initialize();
215
216 auto& kernel = system.Kernel(); 216 auto& kernel = system.Kernel();
217 auto& scheduler = *kernel.CurrentScheduler(); 217 auto& scheduler = *kernel.CurrentScheduler();
218 auto* thread = scheduler.GetSchedulerCurrentThread(); 218 auto* thread = scheduler.GetSchedulerCurrentThread();
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index 148dd3e39..66e46c4ba 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -16,6 +16,7 @@
16#include "common/settings.h" 16#include "common/settings.h"
17#include "common/string_util.h" 17#include "common/string_util.h"
18#include "core/arm/arm_interface.h" 18#include "core/arm/arm_interface.h"
19#include "core/arm/debug.h"
19#include "core/core.h" 20#include "core/core.h"
20#include "core/debugger/gdbstub.h" 21#include "core/debugger/gdbstub.h"
21#include "core/debugger/gdbstub_arch.h" 22#include "core/debugger/gdbstub_arch.h"
@@ -310,7 +311,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
310 const auto mem{Common::HexStringToVector(mem_substr, false)}; 311 const auto mem{Common::HexStringToVector(mem_substr, false)};
311 312
312 if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { 313 if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) {
313 system.InvalidateCpuInstructionCacheRange(addr, size); 314 Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size);
314 SendReply(GDB_STUB_REPLY_OK); 315 SendReply(GDB_STUB_REPLY_OK);
315 } else { 316 } else {
316 SendReply(GDB_STUB_REPLY_ERR); 317 SendReply(GDB_STUB_REPLY_ERR);
@@ -363,7 +364,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) {
363 case BreakpointType::Software: 364 case BreakpointType::Software:
364 replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); 365 replaced_instructions[addr] = system.ApplicationMemory().Read32(addr);
365 system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); 366 system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction());
366 system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); 367 Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32));
367 success = true; 368 success = true;
368 break; 369 break;
369 case BreakpointType::WriteWatch: 370 case BreakpointType::WriteWatch:
@@ -411,7 +412,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
411 const auto orig_insn{replaced_instructions.find(addr)}; 412 const auto orig_insn{replaced_instructions.find(addr)};
412 if (orig_insn != replaced_instructions.end()) { 413 if (orig_insn != replaced_instructions.end()) {
413 system.ApplicationMemory().Write32(addr, orig_insn->second); 414 system.ApplicationMemory().Write32(addr, orig_insn->second);
414 system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); 415 Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32));
415 replaced_instructions.erase(addr); 416 replaced_instructions.erase(addr);
416 success = true; 417 success = true;
417 } 418 }
@@ -442,114 +443,6 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) {
442 } 443 }
443} 444}
444 445
445// Structure offsets are from Atmosphere
446// See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp
447
448static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory,
449 const Kernel::KThread& thread) {
450 // Read thread type from TLS
451 const VAddr tls_thread_type{memory.Read32(thread.GetTlsAddress() + 0x1fc)};
452 const VAddr argument_thread_type{thread.GetArgument()};
453
454 if (argument_thread_type && tls_thread_type != argument_thread_type) {
455 // Probably not created by nnsdk, no name available.
456 return std::nullopt;
457 }
458
459 if (!tls_thread_type) {
460 return std::nullopt;
461 }
462
463 const u16 version{memory.Read16(tls_thread_type + 0x26)};
464 VAddr name_pointer{};
465 if (version == 1) {
466 name_pointer = memory.Read32(tls_thread_type + 0xe4);
467 } else {
468 name_pointer = memory.Read32(tls_thread_type + 0xe8);
469 }
470
471 if (!name_pointer) {
472 // No name provided.
473 return std::nullopt;
474 }
475
476 return memory.ReadCString(name_pointer, 256);
477}
478
479static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory,
480 const Kernel::KThread& thread) {
481 // Read thread type from TLS
482 const VAddr tls_thread_type{memory.Read64(thread.GetTlsAddress() + 0x1f8)};
483 const VAddr argument_thread_type{thread.GetArgument()};
484
485 if (argument_thread_type && tls_thread_type != argument_thread_type) {
486 // Probably not created by nnsdk, no name available.
487 return std::nullopt;
488 }
489
490 if (!tls_thread_type) {
491 return std::nullopt;
492 }
493
494 const u16 version{memory.Read16(tls_thread_type + 0x46)};
495 VAddr name_pointer{};
496 if (version == 1) {
497 name_pointer = memory.Read64(tls_thread_type + 0x1a0);
498 } else {
499 name_pointer = memory.Read64(tls_thread_type + 0x1a8);
500 }
501
502 if (!name_pointer) {
503 // No name provided.
504 return std::nullopt;
505 }
506
507 return memory.ReadCString(name_pointer, 256);
508}
509
510static std::optional<std::string> GetThreadName(Core::System& system,
511 const Kernel::KThread& thread) {
512 if (system.ApplicationProcess()->Is64Bit()) {
513 return GetNameFromThreadType64(system.ApplicationMemory(), thread);
514 } else {
515 return GetNameFromThreadType32(system.ApplicationMemory(), thread);
516 }
517}
518
519static std::string_view GetThreadWaitReason(const Kernel::KThread& thread) {
520 switch (thread.GetWaitReasonForDebugging()) {
521 case Kernel::ThreadWaitReasonForDebugging::Sleep:
522 return "Sleep";
523 case Kernel::ThreadWaitReasonForDebugging::IPC:
524 return "IPC";
525 case Kernel::ThreadWaitReasonForDebugging::Synchronization:
526 return "Synchronization";
527 case Kernel::ThreadWaitReasonForDebugging::ConditionVar:
528 return "ConditionVar";
529 case Kernel::ThreadWaitReasonForDebugging::Arbitration:
530 return "Arbitration";
531 case Kernel::ThreadWaitReasonForDebugging::Suspended:
532 return "Suspended";
533 default:
534 return "Unknown";
535 }
536}
537
538static std::string GetThreadState(const Kernel::KThread& thread) {
539 switch (thread.GetState()) {
540 case Kernel::ThreadState::Initialized:
541 return "Initialized";
542 case Kernel::ThreadState::Waiting:
543 return fmt::format("Waiting ({})", GetThreadWaitReason(thread));
544 case Kernel::ThreadState::Runnable:
545 return "Runnable";
546 case Kernel::ThreadState::Terminated:
547 return "Terminated";
548 default:
549 return "Unknown";
550 }
551}
552
553static std::string PaginateBuffer(std::string_view buffer, std::string_view request) { 446static std::string PaginateBuffer(std::string_view buffer, std::string_view request) {
554 const auto amount{request.substr(request.find(',') + 1)}; 447 const auto amount{request.substr(request.find(',') + 1)};
555 const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))}; 448 const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))};
@@ -562,120 +455,6 @@ static std::string PaginateBuffer(std::string_view buffer, std::string_view requ
562 } 455 }
563} 456}
564 457
565static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) {
566 Kernel::KMemoryInfo mem_info;
567 Kernel::Svc::MemoryInfo svc_mem_info;
568 Kernel::Svc::PageInfo page_info;
569 VAddr cur_addr{base};
570
571 // Expect: r-x Code (.text)
572 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
573 svc_mem_info = mem_info.GetSvcMemoryInfo();
574 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
575 if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
576 svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
577 return cur_addr - 1;
578 }
579
580 // Expect: r-- Code (.rodata)
581 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
582 svc_mem_info = mem_info.GetSvcMemoryInfo();
583 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
584 if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
585 svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
586 return cur_addr - 1;
587 }
588
589 // Expect: rw- CodeData (.data)
590 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
591 svc_mem_info = mem_info.GetSvcMemoryInfo();
592 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
593 return cur_addr - 1;
594}
595
596static Loader::AppLoader::Modules FindModules(Core::System& system) {
597 Loader::AppLoader::Modules modules;
598
599 auto& page_table = system.ApplicationProcess()->GetPageTable();
600 auto& memory = system.ApplicationMemory();
601 VAddr cur_addr = 0;
602
603 // Look for executable sections in Code or AliasCode regions.
604 while (true) {
605 Kernel::KMemoryInfo mem_info{};
606 Kernel::Svc::PageInfo page_info{};
607 R_ASSERT(
608 page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
609 auto svc_mem_info = mem_info.GetSvcMemoryInfo();
610
611 if (svc_mem_info.permission == Kernel::Svc::MemoryPermission::ReadExecute &&
612 (svc_mem_info.state == Kernel::Svc::MemoryState::Code ||
613 svc_mem_info.state == Kernel::Svc::MemoryState::AliasCode)) {
614 // Try to read the module name from its path.
615 constexpr s32 PathLengthMax = 0x200;
616 struct {
617 u32 zero;
618 s32 path_length;
619 std::array<char, PathLengthMax> path;
620 } module_path;
621
622 if (memory.ReadBlock(svc_mem_info.base_address + svc_mem_info.size, &module_path,
623 sizeof(module_path))) {
624 if (module_path.zero == 0 && module_path.path_length > 0) {
625 // Truncate module name.
626 module_path.path[PathLengthMax - 1] = '\0';
627
628 // Ignore leading directories.
629 char* path_pointer = module_path.path.data();
630
631 for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) &&
632 module_path.path[i] != '\0';
633 i++) {
634 if (module_path.path[i] == '/' || module_path.path[i] == '\\') {
635 path_pointer = module_path.path.data() + i + 1;
636 }
637 }
638
639 // Insert output.
640 modules.emplace(svc_mem_info.base_address, path_pointer);
641 }
642 }
643 }
644
645 // Check if we're done.
646 const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size;
647 if (next_address <= cur_addr) {
648 break;
649 }
650
651 cur_addr = next_address;
652 }
653
654 return modules;
655}
656
657static VAddr FindMainModuleEntrypoint(Core::System& system) {
658 Loader::AppLoader::Modules modules;
659 system.GetAppLoader().ReadNSOModules(modules);
660
661 // Do we have a module named main?
662 const auto main = std::find_if(modules.begin(), modules.end(),
663 [](const auto& key) { return key.second == "main"; });
664
665 if (main != modules.end()) {
666 return main->first;
667 }
668
669 // Do we have any loaded executable sections?
670 modules = FindModules(system);
671 if (!modules.empty()) {
672 return modules.begin()->first;
673 }
674
675 // As a last resort, use the start of the code region.
676 return GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart());
677}
678
679void GDBStub::HandleQuery(std::string_view command) { 458void GDBStub::HandleQuery(std::string_view command) {
680 if (command.starts_with("TStatus")) { 459 if (command.starts_with("TStatus")) {
681 // no tracepoint support 460 // no tracepoint support
@@ -687,10 +466,10 @@ void GDBStub::HandleQuery(std::string_view command) {
687 const auto target_xml{arch->GetTargetXML()}; 466 const auto target_xml{arch->GetTargetXML()};
688 SendReply(PaginateBuffer(target_xml, command.substr(30))); 467 SendReply(PaginateBuffer(target_xml, command.substr(30)));
689 } else if (command.starts_with("Offsets")) { 468 } else if (command.starts_with("Offsets")) {
690 const auto main_offset = FindMainModuleEntrypoint(system); 469 const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess());
691 SendReply(fmt::format("TextSeg={:x}", main_offset)); 470 SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset)));
692 } else if (command.starts_with("Xfer:libraries:read::")) { 471 } else if (command.starts_with("Xfer:libraries:read::")) {
693 auto modules = FindModules(system); 472 auto modules = Core::FindModules(system.ApplicationProcess());
694 473
695 std::string buffer; 474 std::string buffer;
696 buffer += R"(<?xml version="1.0"?>)"; 475 buffer += R"(<?xml version="1.0"?>)";
@@ -720,14 +499,14 @@ void GDBStub::HandleQuery(std::string_view command) {
720 499
721 const auto& threads = system.ApplicationProcess()->GetThreadList(); 500 const auto& threads = system.ApplicationProcess()->GetThreadList();
722 for (const auto& thread : threads) { 501 for (const auto& thread : threads) {
723 auto thread_name{GetThreadName(system, thread)}; 502 auto thread_name{Core::GetThreadName(&thread)};
724 if (!thread_name) { 503 if (!thread_name) {
725 thread_name = fmt::format("Thread {:d}", thread.GetThreadId()); 504 thread_name = fmt::format("Thread {:d}", thread.GetThreadId());
726 } 505 }
727 506
728 buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)", 507 buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)",
729 thread.GetThreadId(), thread.GetActiveCore(), 508 thread.GetThreadId(), thread.GetActiveCore(),
730 EscapeXML(*thread_name), GetThreadState(thread)); 509 EscapeXML(*thread_name), GetThreadState(&thread));
731 } 510 }
732 511
733 buffer += "</threads>"; 512 buffer += "</threads>";
@@ -856,7 +635,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
856 reply = "Fastmem is not enabled.\n"; 635 reply = "Fastmem is not enabled.\n";
857 } 636 }
858 } else if (command_str == "get info") { 637 } else if (command_str == "get info") {
859 auto modules = FindModules(system); 638 auto modules = Core::FindModules(process);
860 639
861 reply = fmt::format("Process: {:#x} ({})\n" 640 reply = fmt::format("Process: {:#x} ({})\n"
862 "Program Id: {:#018x}\n", 641 "Program Id: {:#018x}\n",
@@ -880,7 +659,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
880 659
881 for (const auto& [vaddr, name] : modules) { 660 for (const auto& [vaddr, name] : modules) {
882 reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, 661 reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
883 GetModuleEnd(page_table, vaddr), name); 662 GetInteger(Core::GetModuleEnd(process, vaddr)), name);
884 } 663 }
885 } else if (command_str == "get mappings") { 664 } else if (command_str == "get mappings") {
886 reply = "Mappings:\n"; 665 reply = "Mappings:\n";
diff --git a/src/core/debugger/gdbstub_arch.cpp b/src/core/debugger/gdbstub_arch.cpp
index 75c94a91a..f2a407dc8 100644
--- a/src/core/debugger/gdbstub_arch.cpp
+++ b/src/core/debugger/gdbstub_arch.cpp
@@ -24,21 +24,6 @@ static std::string ValueToHex(const T value) {
24 return Common::HexToString(mem); 24 return Common::HexToString(mem);
25} 25}
26 26
27template <typename T>
28static T GetSIMDRegister(const std::array<u32, 64>& simd_regs, size_t offset) {
29 static_assert(std::is_trivially_copyable_v<T>);
30 T value{};
31 std::memcpy(&value, reinterpret_cast<const u8*>(simd_regs.data()) + sizeof(T) * offset,
32 sizeof(T));
33 return value;
34}
35
36template <typename T>
37static void PutSIMDRegister(std::array<u32, 64>& simd_regs, size_t offset, const T value) {
38 static_assert(std::is_trivially_copyable_v<T>);
39 std::memcpy(reinterpret_cast<u8*>(simd_regs.data()) + sizeof(T) * offset, &value, sizeof(T));
40}
41
42// For sample XML files see the GDB source /gdb/features 27// For sample XML files see the GDB source /gdb/features
43// This XML defines what the registers are for this specific ARM device 28// This XML defines what the registers are for this specific ARM device
44std::string_view GDBStubA64::GetTargetXML() const { 29std::string_view GDBStubA64::GetTargetXML() const {
@@ -184,12 +169,16 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const
184 return ""; 169 return "";
185 } 170 }
186 171
187 const auto& context{thread->GetContext64()}; 172 const auto& context{thread->GetContext()};
188 const auto& gprs{context.cpu_registers}; 173 const auto& gprs{context.r};
189 const auto& fprs{context.vector_registers}; 174 const auto& fprs{context.v};
190 175
191 if (id < SP_REGISTER) { 176 if (id < FP_REGISTER) {
192 return ValueToHex(gprs[id]); 177 return ValueToHex(gprs[id]);
178 } else if (id == FP_REGISTER) {
179 return ValueToHex(context.fp);
180 } else if (id == LR_REGISTER) {
181 return ValueToHex(context.lr);
193 } else if (id == SP_REGISTER) { 182 } else if (id == SP_REGISTER) {
194 return ValueToHex(context.sp); 183 return ValueToHex(context.sp);
195 } else if (id == PC_REGISTER) { 184 } else if (id == PC_REGISTER) {
@@ -212,10 +201,14 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
212 return; 201 return;
213 } 202 }
214 203
215 auto& context{thread->GetContext64()}; 204 auto& context{thread->GetContext()};
216 205
217 if (id < SP_REGISTER) { 206 if (id < FP_REGISTER) {
218 context.cpu_registers[id] = HexToValue<u64>(value); 207 context.r[id] = HexToValue<u64>(value);
208 } else if (id == FP_REGISTER) {
209 context.fp = HexToValue<u64>(value);
210 } else if (id == LR_REGISTER) {
211 context.lr = HexToValue<u64>(value);
219 } else if (id == SP_REGISTER) { 212 } else if (id == SP_REGISTER) {
220 context.sp = HexToValue<u64>(value); 213 context.sp = HexToValue<u64>(value);
221 } else if (id == PC_REGISTER) { 214 } else if (id == PC_REGISTER) {
@@ -223,7 +216,7 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
223 } else if (id == PSTATE_REGISTER) { 216 } else if (id == PSTATE_REGISTER) {
224 context.pstate = HexToValue<u32>(value); 217 context.pstate = HexToValue<u32>(value);
225 } else if (id >= Q0_REGISTER && id < FPSR_REGISTER) { 218 } else if (id >= Q0_REGISTER && id < FPSR_REGISTER) {
226 context.vector_registers[id - Q0_REGISTER] = HexToValue<u128>(value); 219 context.v[id - Q0_REGISTER] = HexToValue<u128>(value);
227 } else if (id == FPSR_REGISTER) { 220 } else if (id == FPSR_REGISTER) {
228 context.fpsr = HexToValue<u32>(value); 221 context.fpsr = HexToValue<u32>(value);
229 } else if (id == FPCR_REGISTER) { 222 } else if (id == FPCR_REGISTER) {
@@ -381,22 +374,20 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const
381 return ""; 374 return "";
382 } 375 }
383 376
384 const auto& context{thread->GetContext32()}; 377 const auto& context{thread->GetContext()};
385 const auto& gprs{context.cpu_registers}; 378 const auto& gprs{context.r};
386 const auto& fprs{context.extension_registers}; 379 const auto& fprs{context.v};
387 380
388 if (id <= PC_REGISTER) { 381 if (id <= PC_REGISTER) {
389 return ValueToHex(gprs[id]); 382 return ValueToHex(static_cast<u32>(gprs[id]));
390 } else if (id == CPSR_REGISTER) { 383 } else if (id == CPSR_REGISTER) {
391 return ValueToHex(context.cpsr); 384 return ValueToHex(context.pstate);
392 } else if (id >= D0_REGISTER && id < Q0_REGISTER) { 385 } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
393 const u64 dN{GetSIMDRegister<u64>(fprs, id - D0_REGISTER)}; 386 return ValueToHex(fprs[id - D0_REGISTER][0]);
394 return ValueToHex(dN);
395 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { 387 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
396 const u128 qN{GetSIMDRegister<u128>(fprs, id - Q0_REGISTER)}; 388 return ValueToHex(fprs[id - Q0_REGISTER]);
397 return ValueToHex(qN);
398 } else if (id == FPSCR_REGISTER) { 389 } else if (id == FPSCR_REGISTER) {
399 return ValueToHex(context.fpscr); 390 return ValueToHex(context.fpcr | context.fpsr);
400 } else { 391 } else {
401 return ""; 392 return "";
402 } 393 }
@@ -407,19 +398,20 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
407 return; 398 return;
408 } 399 }
409 400
410 auto& context{thread->GetContext32()}; 401 auto& context{thread->GetContext()};
411 auto& fprs{context.extension_registers}; 402 auto& fprs{context.v};
412 403
413 if (id <= PC_REGISTER) { 404 if (id <= PC_REGISTER) {
414 context.cpu_registers[id] = HexToValue<u32>(value); 405 context.r[id] = HexToValue<u32>(value);
415 } else if (id == CPSR_REGISTER) { 406 } else if (id == CPSR_REGISTER) {
416 context.cpsr = HexToValue<u32>(value); 407 context.pstate = HexToValue<u32>(value);
417 } else if (id >= D0_REGISTER && id < Q0_REGISTER) { 408 } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
418 PutSIMDRegister(fprs, id - D0_REGISTER, HexToValue<u64>(value)); 409 fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0};
419 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { 410 } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
420 PutSIMDRegister(fprs, id - Q0_REGISTER, HexToValue<u128>(value)); 411 fprs[id - Q0_REGISTER] = HexToValue<u128>(value);
421 } else if (id == FPSCR_REGISTER) { 412 } else if (id == FPSCR_REGISTER) {
422 context.fpscr = HexToValue<u32>(value); 413 context.fpcr = HexToValue<u32>(value);
414 context.fpsr = HexToValue<u32>(value);
423 } 415 }
424} 416}
425 417
diff --git a/src/core/debugger/gdbstub_arch.h b/src/core/debugger/gdbstub_arch.h
index 34530c788..d53714d69 100644
--- a/src/core/debugger/gdbstub_arch.h
+++ b/src/core/debugger/gdbstub_arch.h
@@ -36,6 +36,7 @@ public:
36 u32 BreakpointInstruction() const override; 36 u32 BreakpointInstruction() const override;
37 37
38private: 38private:
39 static constexpr u32 FP_REGISTER = 29;
39 static constexpr u32 LR_REGISTER = 30; 40 static constexpr u32 LR_REGISTER = 30;
40 static constexpr u32 SP_REGISTER = 31; 41 static constexpr u32 SP_REGISTER = 31;
41 static constexpr u32 PC_REGISTER = 32; 42 static constexpr u32 PC_REGISTER = 32;
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index f1d3e4129..dd9cca103 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <cstring> 4#include <cstring>
5#include <span>
5#include <string_view> 6#include <string_view>
6#include "common/alignment.h" 7#include "common/alignment.h"
7#include "common/assert.h" 8#include "common/assert.h"
@@ -134,7 +135,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir,
134 135
135 child->size = child->source->GetSize(); 136 child->size = child->source->GetSize();
136 137
137 AddFile(parent, child); 138 AddFile(parent, std::move(child));
138 } 139 }
139 140
140 for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) { 141 for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) {
@@ -163,36 +164,24 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir,
163 164
164bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, 165bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
165 std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { 166 std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) {
166 // Check whether it's already in the known directories.
167 const auto [it, is_new] = directories.emplace(dir_ctx->path, nullptr);
168 if (!is_new) {
169 return false;
170 }
171
172 // Add a new directory. 167 // Add a new directory.
173 num_dirs++; 168 num_dirs++;
174 dir_table_size += 169 dir_table_size +=
175 sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); 170 sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4);
176 dir_ctx->parent = parent_dir_ctx; 171 dir_ctx->parent = std::move(parent_dir_ctx);
177 it->second = dir_ctx; 172 directories.emplace_back(std::move(dir_ctx));
178 173
179 return true; 174 return true;
180} 175}
181 176
182bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, 177bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx,
183 std::shared_ptr<RomFSBuildFileContext> file_ctx) { 178 std::shared_ptr<RomFSBuildFileContext> file_ctx) {
184 // Check whether it's already in the known files.
185 const auto [it, is_new] = files.emplace(file_ctx->path, nullptr);
186 if (!is_new) {
187 return false;
188 }
189
190 // Add a new file. 179 // Add a new file.
191 num_files++; 180 num_files++;
192 file_table_size += 181 file_table_size +=
193 sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); 182 sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4);
194 file_ctx->parent = parent_dir_ctx; 183 file_ctx->parent = std::move(parent_dir_ctx);
195 it->second = file_ctx; 184 files.emplace_back(std::move(file_ctx));
196 185
197 return true; 186 return true;
198} 187}
@@ -201,7 +190,7 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_)
201 : base(std::move(base_)), ext(std::move(ext_)) { 190 : base(std::move(base_)), ext(std::move(ext_)) {
202 root = std::make_shared<RomFSBuildDirectoryContext>(); 191 root = std::make_shared<RomFSBuildDirectoryContext>();
203 root->path = "\0"; 192 root->path = "\0";
204 directories.emplace(root->path, root); 193 directories.emplace_back(root);
205 num_dirs = 1; 194 num_dirs = 1;
206 dir_table_size = 0x18; 195 dir_table_size = 0x18;
207 196
@@ -210,28 +199,43 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_)
210 199
211RomFSBuildContext::~RomFSBuildContext() = default; 200RomFSBuildContext::~RomFSBuildContext() = default;
212 201
213std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { 202std::vector<std::pair<u64, VirtualFile>> RomFSBuildContext::Build() {
214 const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); 203 const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs);
215 const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); 204 const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files);
216 dir_hash_table_size = 4 * dir_hash_table_entry_count; 205 dir_hash_table_size = 4 * dir_hash_table_entry_count;
217 file_hash_table_size = 4 * file_hash_table_entry_count; 206 file_hash_table_size = 4 * file_hash_table_entry_count;
218 207
219 // Assign metadata pointers 208 // Assign metadata pointers.
220 RomFSHeader header{}; 209 RomFSHeader header{};
221 210
222 std::vector<u32> dir_hash_table(dir_hash_table_entry_count, ROMFS_ENTRY_EMPTY); 211 std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size +
223 std::vector<u32> file_hash_table(file_hash_table_entry_count, ROMFS_ENTRY_EMPTY); 212 dir_table_size);
224 213 u32* const dir_hash_table_pointer = reinterpret_cast<u32*>(metadata.data());
225 std::vector<u8> dir_table(dir_table_size); 214 u8* const dir_table_pointer = metadata.data() + dir_hash_table_size;
226 std::vector<u8> file_table(file_table_size); 215 u32* const file_hash_table_pointer =
227 216 reinterpret_cast<u32*>(metadata.data() + dir_hash_table_size + dir_table_size);
228 std::shared_ptr<RomFSBuildFileContext> cur_file; 217 u8* const file_table_pointer =
218 metadata.data() + dir_hash_table_size + dir_table_size + file_hash_table_size;
219
220 std::span<u32> dir_hash_table(dir_hash_table_pointer, dir_hash_table_entry_count);
221 std::span<u32> file_hash_table(file_hash_table_pointer, file_hash_table_entry_count);
222 std::span<u8> dir_table(dir_table_pointer, dir_table_size);
223 std::span<u8> file_table(file_table_pointer, file_table_size);
224
225 // Initialize hash tables.
226 std::memset(dir_hash_table.data(), 0xFF, dir_hash_table.size_bytes());
227 std::memset(file_hash_table.data(), 0xFF, file_hash_table.size_bytes());
228
229 // Sort tables by name.
230 std::sort(files.begin(), files.end(),
231 [](const auto& a, const auto& b) { return a->path < b->path; });
232 std::sort(directories.begin(), directories.end(),
233 [](const auto& a, const auto& b) { return a->path < b->path; });
229 234
230 // Determine file offsets. 235 // Determine file offsets.
231 u32 entry_offset = 0; 236 u32 entry_offset = 0;
232 std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; 237 std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr;
233 for (const auto& it : files) { 238 for (const auto& cur_file : files) {
234 cur_file = it.second;
235 file_partition_size = Common::AlignUp(file_partition_size, 16); 239 file_partition_size = Common::AlignUp(file_partition_size, 16);
236 cur_file->offset = file_partition_size; 240 cur_file->offset = file_partition_size;
237 file_partition_size += cur_file->size; 241 file_partition_size += cur_file->size;
@@ -243,34 +247,48 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
243 } 247 }
244 // Assign deferred parent/sibling ownership. 248 // Assign deferred parent/sibling ownership.
245 for (auto it = files.rbegin(); it != files.rend(); ++it) { 249 for (auto it = files.rbegin(); it != files.rend(); ++it) {
246 cur_file = it->second; 250 auto& cur_file = *it;
247 cur_file->sibling = cur_file->parent->file; 251 cur_file->sibling = cur_file->parent->file;
248 cur_file->parent->file = cur_file; 252 cur_file->parent->file = cur_file;
249 } 253 }
250 254
251 std::shared_ptr<RomFSBuildDirectoryContext> cur_dir;
252
253 // Determine directory offsets. 255 // Determine directory offsets.
254 entry_offset = 0; 256 entry_offset = 0;
255 for (const auto& it : directories) { 257 for (const auto& cur_dir : directories) {
256 cur_dir = it.second;
257 cur_dir->entry_offset = entry_offset; 258 cur_dir->entry_offset = entry_offset;
258 entry_offset += 259 entry_offset +=
259 static_cast<u32>(sizeof(RomFSDirectoryEntry) + 260 static_cast<u32>(sizeof(RomFSDirectoryEntry) +
260 Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4)); 261 Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4));
261 } 262 }
262 // Assign deferred parent/sibling ownership. 263 // Assign deferred parent/sibling ownership.
263 for (auto it = directories.rbegin(); it->second != root; ++it) { 264 for (auto it = directories.rbegin(); (*it) != root; ++it) {
264 cur_dir = it->second; 265 auto& cur_dir = *it;
265 cur_dir->sibling = cur_dir->parent->child; 266 cur_dir->sibling = cur_dir->parent->child;
266 cur_dir->parent->child = cur_dir; 267 cur_dir->parent->child = cur_dir;
267 } 268 }
268 269
269 std::multimap<u64, VirtualFile> out; 270 // Create output map.
271 std::vector<std::pair<u64, VirtualFile>> out;
272 out.reserve(num_files + 2);
273
274 // Set header fields.
275 header.header_size = sizeof(RomFSHeader);
276 header.file_hash_table_size = file_hash_table_size;
277 header.file_table_size = file_table_size;
278 header.dir_hash_table_size = dir_hash_table_size;
279 header.dir_table_size = dir_table_size;
280 header.file_partition_ofs = ROMFS_FILEPARTITION_OFS;
281 header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4);
282 header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size;
283 header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size;
284 header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size;
285
286 std::vector<u8> header_data(sizeof(RomFSHeader));
287 std::memcpy(header_data.data(), &header, header_data.size());
288 out.emplace_back(0, std::make_shared<VectorVfsFile>(std::move(header_data)));
270 289
271 // Populate file tables. 290 // Populate file tables.
272 for (const auto& it : files) { 291 for (const auto& cur_file : files) {
273 cur_file = it.second;
274 RomFSFileEntry cur_entry{}; 292 RomFSFileEntry cur_entry{};
275 293
276 cur_entry.parent = cur_file->parent->entry_offset; 294 cur_entry.parent = cur_file->parent->entry_offset;
@@ -287,7 +305,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
287 305
288 cur_entry.name_size = name_size; 306 cur_entry.name_size = name_size;
289 307
290 out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source)); 308 out.emplace_back(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source));
291 std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); 309 std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry));
292 std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, 310 std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0,
293 Common::AlignUp(cur_entry.name_size, 4)); 311 Common::AlignUp(cur_entry.name_size, 4));
@@ -296,8 +314,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
296 } 314 }
297 315
298 // Populate dir tables. 316 // Populate dir tables.
299 for (const auto& it : directories) { 317 for (const auto& cur_dir : directories) {
300 cur_dir = it.second;
301 RomFSDirectoryEntry cur_entry{}; 318 RomFSDirectoryEntry cur_entry{};
302 319
303 cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset; 320 cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset;
@@ -323,34 +340,13 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
323 cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); 340 cur_dir->path.data() + cur_dir->cur_path_ofs, name_size);
324 } 341 }
325 342
326 // Set header fields. 343 // Write metadata.
327 header.header_size = sizeof(RomFSHeader); 344 out.emplace_back(header.dir_hash_table_ofs,
328 header.file_hash_table_size = file_hash_table_size; 345 std::make_shared<VectorVfsFile>(std::move(metadata)));
329 header.file_table_size = file_table_size;
330 header.dir_hash_table_size = dir_hash_table_size;
331 header.dir_table_size = dir_table_size;
332 header.file_partition_ofs = ROMFS_FILEPARTITION_OFS;
333 header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4);
334 header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size;
335 header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size;
336 header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size;
337
338 std::vector<u8> header_data(sizeof(RomFSHeader));
339 std::memcpy(header_data.data(), &header, header_data.size());
340 out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data)));
341 346
342 std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + 347 // Sort the output.
343 dir_table_size); 348 std::sort(out.begin(), out.end(),
344 std::size_t index = 0; 349 [](const auto& a, const auto& b) { return a.first < b.first; });
345 std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32));
346 index += dir_hash_table.size() * sizeof(u32);
347 std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size());
348 index += dir_table.size();
349 std::memcpy(metadata.data() + index, file_hash_table.data(),
350 file_hash_table.size() * sizeof(u32));
351 index += file_hash_table.size() * sizeof(u32);
352 std::memcpy(metadata.data() + index, file_table.data(), file_table.size());
353 out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata)));
354 350
355 return out; 351 return out;
356} 352}
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h
index 06e5d5a47..f387c79f1 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.h
+++ b/src/core/file_sys/fsmitm_romfsbuild.h
@@ -22,14 +22,14 @@ public:
22 ~RomFSBuildContext(); 22 ~RomFSBuildContext();
23 23
24 // This finalizes the context. 24 // This finalizes the context.
25 std::multimap<u64, VirtualFile> Build(); 25 std::vector<std::pair<u64, VirtualFile>> Build();
26 26
27private: 27private:
28 VirtualDir base; 28 VirtualDir base;
29 VirtualDir ext; 29 VirtualDir ext;
30 std::shared_ptr<RomFSBuildDirectoryContext> root; 30 std::shared_ptr<RomFSBuildDirectoryContext> root;
31 std::map<std::string, std::shared_ptr<RomFSBuildDirectoryContext>, std::less<>> directories; 31 std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> directories;
32 std::map<std::string, std::shared_ptr<RomFSBuildFileContext>, std::less<>> files; 32 std::vector<std::shared_ptr<RomFSBuildFileContext>> files;
33 u64 num_dirs = 0; 33 u64 num_dirs = 0;
34 u64 num_files = 0; 34 u64 num_files = 0;
35 u64 dir_table_size = 0; 35 u64 dir_table_size = 0;
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index 6de2103a0..6182598ae 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -55,44 +55,68 @@ struct FileEntry {
55}; 55};
56static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); 56static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
57 57
58template <typename Entry> 58struct RomFSTraversalContext {
59std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) { 59 RomFSHeader header;
60 Entry entry{}; 60 VirtualFile file;
61 if (file->ReadObject(&entry, offset) != sizeof(Entry)) 61 std::vector<u8> directory_meta;
62 return {}; 62 std::vector<u8> file_meta;
63 std::string string(entry.name_length, '\0'); 63};
64 if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size()) 64
65template <typename EntryType, auto Member>
66std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, size_t offset) {
67 const size_t entry_end = offset + sizeof(EntryType);
68 const std::vector<u8>& vec = ctx.*Member;
69 const size_t size = vec.size();
70 const u8* data = vec.data();
71 EntryType entry{};
72
73 if (entry_end > size) {
65 return {}; 74 return {};
66 return {entry, string}; 75 }
76 std::memcpy(&entry, data + offset, sizeof(EntryType));
77
78 const size_t name_length = std::min(entry_end + entry.name_length, size) - entry_end;
79 std::string name(reinterpret_cast<const char*>(data + entry_end), name_length);
80
81 return {entry, std::move(name)};
82}
83
84std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx,
85 size_t directory_offset) {
86 return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset);
87}
88
89std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx,
90 size_t file_offset) {
91 return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset);
67} 92}
68 93
69void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset, 94void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset,
70 u32 this_file_offset, std::shared_ptr<VectorVfsDirectory>& parent) { 95 std::shared_ptr<VectorVfsDirectory>& parent) {
71 while (this_file_offset != ROMFS_ENTRY_EMPTY) { 96 while (this_file_offset != ROMFS_ENTRY_EMPTY) {
72 auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); 97 auto entry = GetFileEntry(ctx, this_file_offset);
73 98
74 parent->AddFile(std::make_shared<OffsetVfsFile>( 99 parent->AddFile(std::make_shared<OffsetVfsFile>(ctx.file, entry.first.size,
75 file, entry.first.size, entry.first.offset + data_offset, entry.second)); 100 entry.first.offset + ctx.header.data_offset,
101 std::move(entry.second)));
76 102
77 this_file_offset = entry.first.sibling; 103 this_file_offset = entry.first.sibling;
78 } 104 }
79} 105}
80 106
81void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset, 107void ProcessDirectory(const RomFSTraversalContext& ctx, u32 this_dir_offset,
82 std::size_t data_offset, u32 this_dir_offset,
83 std::shared_ptr<VectorVfsDirectory>& parent) { 108 std::shared_ptr<VectorVfsDirectory>& parent) {
84 while (this_dir_offset != ROMFS_ENTRY_EMPTY) { 109 while (this_dir_offset != ROMFS_ENTRY_EMPTY) {
85 auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); 110 auto entry = GetDirectoryEntry(ctx, this_dir_offset);
86 auto current = std::make_shared<VectorVfsDirectory>( 111 auto current = std::make_shared<VectorVfsDirectory>(
87 std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); 112 std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second);
88 113
89 if (entry.first.child_file != ROMFS_ENTRY_EMPTY) { 114 if (entry.first.child_file != ROMFS_ENTRY_EMPTY) {
90 ProcessFile(file, file_offset, data_offset, entry.first.child_file, current); 115 ProcessFile(ctx, entry.first.child_file, current);
91 } 116 }
92 117
93 if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) { 118 if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) {
94 ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir, 119 ProcessDirectory(ctx, entry.first.child_dir, current);
95 current);
96 } 120 }
97 121
98 parent->AddDirectory(current); 122 parent->AddDirectory(current);
@@ -107,22 +131,25 @@ VirtualDir ExtractRomFS(VirtualFile file) {
107 return root_container; 131 return root_container;
108 } 132 }
109 133
110 RomFSHeader header{}; 134 RomFSTraversalContext ctx{};
111 if (file->ReadObject(&header) != sizeof(RomFSHeader)) { 135
112 return root_container; 136 if (file->ReadObject(&ctx.header) != sizeof(RomFSHeader)) {
137 return nullptr;
113 } 138 }
114 139
115 if (header.header_size != sizeof(RomFSHeader)) { 140 if (ctx.header.header_size != sizeof(RomFSHeader)) {
116 return root_container; 141 return nullptr;
117 } 142 }
118 143
119 const u64 file_offset = header.file_meta.offset; 144 ctx.file = file;
120 const u64 dir_offset = header.directory_meta.offset; 145 ctx.directory_meta =
146 file->ReadBytes(ctx.header.directory_meta.size, ctx.header.directory_meta.offset);
147 ctx.file_meta = file->ReadBytes(ctx.header.file_meta.size, ctx.header.file_meta.offset);
121 148
122 ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container); 149 ProcessDirectory(ctx, 0, root_container);
123 150
124 if (auto root = root_container->GetSubdirectory(""); root) { 151 if (auto root = root_container->GetSubdirectory(""); root) {
125 return std::make_shared<CachedVfsDirectory>(std::move(root)); 152 return root;
126 } 153 }
127 154
128 ASSERT(false); 155 ASSERT(false);
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index a4d060007..8d5d593e8 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -12,8 +12,6 @@
12 12
13namespace FileSys { 13namespace FileSys {
14 14
15constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
16
17namespace { 15namespace {
18 16
19void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) { 17void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
@@ -197,7 +195,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
197 GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 195 GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
198 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); 196 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
199 197
200 const auto size_file = relative_dir->GetFile(SAVE_DATA_SIZE_FILENAME); 198 const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName());
201 if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize)) { 199 if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize)) {
202 return {0, 0}; 200 return {0, 0};
203 } 201 }
@@ -216,7 +214,7 @@ void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 us
216 GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 214 GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
217 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); 215 const auto relative_dir = GetOrCreateDirectoryRelative(dir, path);
218 216
219 const auto size_file = relative_dir->CreateFile(SAVE_DATA_SIZE_FILENAME); 217 const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName());
220 if (size_file == nullptr) { 218 if (size_file == nullptr) {
221 return; 219 return;
222 } 220 }
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 45c7c81fb..e3a0f8cef 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -83,6 +83,10 @@ struct SaveDataSize {
83 u64 journal; 83 u64 journal;
84}; 84};
85 85
86constexpr const char* GetSaveDataSizeFileName() {
87 return ".yuzu_save_size";
88}
89
86/// File system interface to the SaveData archive 90/// File system interface to the SaveData archive
87class SaveDataFactory { 91class SaveDataFactory {
88public: 92public:
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index 168b9cbec..7c7298527 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -59,8 +59,8 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name,
59 return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map))); 59 return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
60} 60}
61 61
62VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::string&& name, 62VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(
63 std::multimap<u64, VirtualFile>&& files) { 63 u8 filler_byte, std::string&& name, std::vector<std::pair<u64, VirtualFile>>&& files) {
64 // Fold trivial cases. 64 // Fold trivial cases.
65 if (files.empty()) { 65 if (files.empty()) {
66 return nullptr; 66 return nullptr;
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index cbddd12bd..b5f3d72e3 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -37,7 +37,7 @@ public:
37 /// Convenience function that turns a map of offsets to files into a concatenated file, filling 37 /// Convenience function that turns a map of offsets to files into a concatenated file, filling
38 /// gaps with a given filler byte. 38 /// gaps with a given filler byte.
39 static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name, 39 static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name,
40 std::multimap<u64, VirtualFile>&& files); 40 std::vector<std::pair<u64, VirtualFile>>&& files);
41 41
42 std::string GetName() const override; 42 std::string GetName() const override;
43 std::size_t GetSize() const override; 43 std::size_t GetSize() const override;
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index 08daca397..5551743fb 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -3,6 +3,7 @@
3 3
4#include <algorithm> 4#include <algorithm>
5#include <set> 5#include <set>
6#include <unordered_set>
6#include <utility> 7#include <utility>
7#include "core/file_sys/vfs_layered.h" 8#include "core/file_sys/vfs_layered.h"
8 9
@@ -59,13 +60,12 @@ std::string LayeredVfsDirectory::GetFullPath() const {
59 60
60std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { 61std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
61 std::vector<VirtualFile> out; 62 std::vector<VirtualFile> out;
62 std::set<std::string, std::less<>> out_names; 63 std::unordered_set<std::string> out_names;
63 64
64 for (const auto& layer : dirs) { 65 for (const auto& layer : dirs) {
65 for (auto& file : layer->GetFiles()) { 66 for (auto& file : layer->GetFiles()) {
66 auto file_name = file->GetName(); 67 const auto [it, is_new] = out_names.emplace(file->GetName());
67 if (!out_names.contains(file_name)) { 68 if (is_new) {
68 out_names.emplace(std::move(file_name));
69 out.emplace_back(std::move(file)); 69 out.emplace_back(std::move(file));
70 } 70 }
71 } 71 }
@@ -75,18 +75,19 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
75} 75}
76 76
77std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const { 77std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
78 std::vector<std::string> names; 78 std::vector<VirtualDir> out;
79 std::unordered_set<std::string> out_names;
80
79 for (const auto& layer : dirs) { 81 for (const auto& layer : dirs) {
80 for (const auto& sd : layer->GetSubdirectories()) { 82 for (const auto& sd : layer->GetSubdirectories()) {
81 if (std::find(names.begin(), names.end(), sd->GetName()) == names.end()) 83 out_names.emplace(sd->GetName());
82 names.push_back(sd->GetName());
83 } 84 }
84 } 85 }
85 86
86 std::vector<VirtualDir> out; 87 out.reserve(out_names.size());
87 out.reserve(names.size()); 88 for (const auto& subdir : out_names) {
88 for (const auto& subdir : names)
89 out.emplace_back(GetSubdirectory(subdir)); 89 out.emplace_back(GetSubdirectory(subdir));
90 }
90 91
91 return out; 92 return out;
92} 93}
diff --git a/src/core/hid/input_interpreter.cpp b/src/core/hid/input_interpreter.cpp
index a6bdd28f2..072f38a68 100644
--- a/src/core/hid/input_interpreter.cpp
+++ b/src/core/hid/input_interpreter.cpp
@@ -20,6 +20,9 @@ InputInterpreter::InputInterpreter(Core::System& system)
20InputInterpreter::~InputInterpreter() = default; 20InputInterpreter::~InputInterpreter() = default;
21 21
22void InputInterpreter::PollInput() { 22void InputInterpreter::PollInput() {
23 if (npad == nullptr) {
24 return;
25 }
23 const auto button_state = npad->GetAndResetPressState(); 26 const auto button_state = npad->GetAndResetPressState();
24 27
25 previous_index = current_index; 28 previous_index = current_index;
diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp
index 40e09e532..11b1b977e 100644
--- a/src/core/hle/kernel/k_client_port.cpp
+++ b/src/core/hle/kernel/k_client_port.cpp
@@ -3,6 +3,7 @@
3 3
4#include "common/scope_exit.h" 4#include "common/scope_exit.h"
5#include "core/hle/kernel/k_client_port.h" 5#include "core/hle/kernel/k_client_port.h"
6#include "core/hle/kernel/k_light_session.h"
6#include "core/hle/kernel/k_port.h" 7#include "core/hle/kernel/k_port.h"
7#include "core/hle/kernel/k_scheduler.h" 8#include "core/hle/kernel/k_scheduler.h"
8#include "core/hle/kernel/k_scoped_resource_reservation.h" 9#include "core/hle/kernel/k_scoped_resource_reservation.h"
@@ -63,6 +64,7 @@ Result KClientPort::CreateSession(KClientSession** out) {
63 R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); 64 R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
64 65
65 // Allocate a session normally. 66 // Allocate a session normally.
67 // TODO: Dynamic resource limits
66 session = KSession::Create(m_kernel); 68 session = KSession::Create(m_kernel);
67 69
68 // Check that we successfully created a session. 70 // Check that we successfully created a session.
@@ -119,4 +121,71 @@ Result KClientPort::CreateSession(KClientSession** out) {
119 R_SUCCEED(); 121 R_SUCCEED();
120} 122}
121 123
124Result KClientPort::CreateLightSession(KLightClientSession** out) {
125 // Declare the session we're going to allocate.
126 KLightSession* session{};
127
128 // Reserve a new session from the resource limit.
129 KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel),
130 Svc::LimitableResource::SessionCountMax);
131 R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
132
133 // Allocate a session normally.
134 // TODO: Dynamic resource limits
135 session = KLightSession::Create(m_kernel);
136
137 // Check that we successfully created a session.
138 R_UNLESS(session != nullptr, ResultOutOfResource);
139
140 // Update the session counts.
141 {
142 ON_RESULT_FAILURE {
143 session->Close();
144 };
145
146 // Atomically increment the number of sessions.
147 s32 new_sessions;
148 {
149 const auto max = m_max_sessions;
150 auto cur_sessions = m_num_sessions.load(std::memory_order_acquire);
151 do {
152 R_UNLESS(cur_sessions < max, ResultOutOfSessions);
153 new_sessions = cur_sessions + 1;
154 } while (!m_num_sessions.compare_exchange_weak(cur_sessions, new_sessions,
155 std::memory_order_relaxed));
156 }
157
158 // Atomically update the peak session tracking.
159 {
160 auto peak = m_peak_sessions.load(std::memory_order_acquire);
161 do {
162 if (peak >= new_sessions) {
163 break;
164 }
165 } while (!m_peak_sessions.compare_exchange_weak(peak, new_sessions,
166 std::memory_order_relaxed));
167 }
168 }
169
170 // Initialize the session.
171 session->Initialize(this, m_parent->GetName());
172
173 // Commit the session reservation.
174 session_reservation.Commit();
175
176 // Register the session.
177 KLightSession::Register(m_kernel, session);
178 ON_RESULT_FAILURE {
179 session->GetClientSession().Close();
180 session->GetServerSession().Close();
181 };
182
183 // Enqueue the session with our parent.
184 R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession())));
185
186 // We succeeded, so set the output.
187 *out = std::addressof(session->GetClientSession());
188 R_SUCCEED();
189}
190
122} // namespace Kernel 191} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h
index 23db06ddf..28b332608 100644
--- a/src/core/hle/kernel/k_client_port.h
+++ b/src/core/hle/kernel/k_client_port.h
@@ -11,6 +11,7 @@
11 11
12namespace Kernel { 12namespace Kernel {
13 13
14class KLightClientSession;
14class KClientSession; 15class KClientSession;
15class KernelCore; 16class KernelCore;
16class KPort; 17class KPort;
@@ -51,6 +52,7 @@ public:
51 bool IsSignaled() const override; 52 bool IsSignaled() const override;
52 53
53 Result CreateSession(KClientSession** out); 54 Result CreateSession(KClientSession** out);
55 Result CreateLightSession(KLightClientSession** out);
54 56
55private: 57private:
56 std::atomic<s32> m_num_sessions{}; 58 std::atomic<s32> m_num_sessions{};
diff --git a/src/core/hle/kernel/k_client_session.cpp b/src/core/hle/kernel/k_client_session.cpp
index 72b66270d..472e8571c 100644
--- a/src/core/hle/kernel/k_client_session.cpp
+++ b/src/core/hle/kernel/k_client_session.cpp
@@ -10,9 +10,7 @@
10 10
11namespace Kernel { 11namespace Kernel {
12 12
13static constexpr u32 MessageBufferSize = 0x100; 13KClientSession::KClientSession(KernelCore& kernel) : KAutoObject{kernel} {}
14
15KClientSession::KClientSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {}
16KClientSession::~KClientSession() = default; 14KClientSession::~KClientSession() = default;
17 15
18void KClientSession::Destroy() { 16void KClientSession::Destroy() {
@@ -22,18 +20,30 @@ void KClientSession::Destroy() {
22 20
23void KClientSession::OnServerClosed() {} 21void KClientSession::OnServerClosed() {}
24 22
25Result KClientSession::SendSyncRequest() { 23Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) {
24 // Create a session request.
25 KSessionRequest* request = KSessionRequest::Create(m_kernel);
26 R_UNLESS(request != nullptr, ResultOutOfResource);
27 SCOPE_EXIT({ request->Close(); });
28
29 // Initialize the request.
30 request->Initialize(nullptr, address, size);
31
32 // Send the request.
33 R_RETURN(m_parent->OnRequest(request));
34}
35
36Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t size) {
26 // Create a session request. 37 // Create a session request.
27 KSessionRequest* request = KSessionRequest::Create(m_kernel); 38 KSessionRequest* request = KSessionRequest::Create(m_kernel);
28 R_UNLESS(request != nullptr, ResultOutOfResource); 39 R_UNLESS(request != nullptr, ResultOutOfResource);
29 SCOPE_EXIT({ request->Close(); }); 40 SCOPE_EXIT({ request->Close(); });
30 41
31 // Initialize the request. 42 // Initialize the request.
32 request->Initialize(nullptr, GetInteger(GetCurrentThread(m_kernel).GetTlsAddress()), 43 request->Initialize(event, address, size);
33 MessageBufferSize);
34 44
35 // Send the request. 45 // Send the request.
36 R_RETURN(m_parent->GetServerSession().OnRequest(request)); 46 R_RETURN(m_parent->OnRequest(request));
37} 47}
38 48
39} // namespace Kernel 49} // namespace Kernel
diff --git a/src/core/hle/kernel/k_client_session.h b/src/core/hle/kernel/k_client_session.h
index 9b62e55e4..a39213e17 100644
--- a/src/core/hle/kernel/k_client_session.h
+++ b/src/core/hle/kernel/k_client_session.h
@@ -9,24 +9,12 @@
9#include "core/hle/kernel/slab_helpers.h" 9#include "core/hle/kernel/slab_helpers.h"
10#include "core/hle/result.h" 10#include "core/hle/result.h"
11 11
12union Result;
13
14namespace Core::Memory {
15class Memory;
16}
17
18namespace Core::Timing {
19class CoreTiming;
20}
21
22namespace Kernel { 12namespace Kernel {
23 13
24class KernelCore; 14class KernelCore;
25class KSession; 15class KSession;
26class KThread;
27 16
28class KClientSession final 17class KClientSession final : public KAutoObject {
29 : public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> {
30 KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); 18 KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject);
31 19
32public: 20public:
@@ -39,13 +27,13 @@ public:
39 } 27 }
40 28
41 void Destroy() override; 29 void Destroy() override;
42 static void PostDestroy(uintptr_t arg) {}
43 30
44 KSession* GetParent() const { 31 KSession* GetParent() const {
45 return m_parent; 32 return m_parent;
46 } 33 }
47 34
48 Result SendSyncRequest(); 35 Result SendSyncRequest(uintptr_t address, size_t size);
36 Result SendAsyncRequest(KEvent* event, uintptr_t address, size_t size);
49 37
50 void OnServerClosed(); 38 void OnServerClosed();
51 39
diff --git a/src/core/hle/kernel/k_light_client_session.cpp b/src/core/hle/kernel/k_light_client_session.cpp
new file mode 100644
index 000000000..8ce3e1ae4
--- /dev/null
+++ b/src/core/hle/kernel/k_light_client_session.cpp
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_light_client_session.h"
5#include "core/hle/kernel/k_light_session.h"
6#include "core/hle/kernel/k_thread.h"
7
8namespace Kernel {
9
10KLightClientSession::KLightClientSession(KernelCore& kernel) : KAutoObject(kernel) {}
11
12KLightClientSession::~KLightClientSession() = default;
13
14void KLightClientSession::Destroy() {
15 m_parent->OnClientClosed();
16}
17
18void KLightClientSession::OnServerClosed() {}
19
20Result KLightClientSession::SendSyncRequest(u32* data) {
21 // Get the request thread.
22 KThread* cur_thread = GetCurrentThreadPointer(m_kernel);
23
24 // Set the light data.
25 cur_thread->SetLightSessionData(data);
26
27 // Send the request.
28 R_RETURN(m_parent->OnRequest(cur_thread));
29}
30
31} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_client_session.h b/src/core/hle/kernel/k_light_client_session.h
new file mode 100644
index 000000000..881a15cbd
--- /dev/null
+++ b/src/core/hle/kernel/k_light_client_session.h
@@ -0,0 +1,39 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/kernel/k_auto_object.h"
7#include "core/hle/result.h"
8
9namespace Kernel {
10
11class KLightSession;
12
13class KLightClientSession final : public KAutoObject {
14 KERNEL_AUTOOBJECT_TRAITS(KLightClientSession, KAutoObject);
15
16public:
17 explicit KLightClientSession(KernelCore& kernel);
18 ~KLightClientSession();
19
20 void Initialize(KLightSession* parent) {
21 // Set member variables.
22 m_parent = parent;
23 }
24
25 virtual void Destroy() override;
26
27 const KLightSession* GetParent() const {
28 return m_parent;
29 }
30
31 Result SendSyncRequest(u32* data);
32
33 void OnServerClosed();
34
35private:
36 KLightSession* m_parent;
37};
38
39} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_server_session.cpp b/src/core/hle/kernel/k_light_server_session.cpp
new file mode 100644
index 000000000..e5ceb01f2
--- /dev/null
+++ b/src/core/hle/kernel/k_light_server_session.cpp
@@ -0,0 +1,247 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_light_server_session.h"
5#include "core/hle/kernel/k_light_session.h"
6#include "core/hle/kernel/k_thread.h"
7#include "core/hle/kernel/k_thread_queue.h"
8#include "core/hle/kernel/svc_results.h"
9
10namespace Kernel {
11
12namespace {
13
14constexpr u64 InvalidThreadId = std::numeric_limits<u64>::max();
15
16class ThreadQueueImplForKLightServerSessionRequest final : public KThreadQueue {
17private:
18 KThread::WaiterList* m_wait_list;
19
20public:
21 ThreadQueueImplForKLightServerSessionRequest(KernelCore& kernel, KThread::WaiterList* wl)
22 : KThreadQueue(kernel), m_wait_list(wl) {}
23
24 virtual void EndWait(KThread* waiting_thread, Result wait_result) override {
25 // Remove the thread from our wait list.
26 m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread));
27
28 // Invoke the base end wait handler.
29 KThreadQueue::EndWait(waiting_thread, wait_result);
30 }
31
32 virtual void CancelWait(KThread* waiting_thread, Result wait_result,
33 bool cancel_timer_task) override {
34 // Remove the thread from our wait list.
35 m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread));
36
37 // Invoke the base cancel wait handler.
38 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
39 }
40};
41
42class ThreadQueueImplForKLightServerSessionReceive final : public KThreadQueue {
43private:
44 KThread** m_server_thread;
45
46public:
47 ThreadQueueImplForKLightServerSessionReceive(KernelCore& kernel, KThread** st)
48 : KThreadQueue(kernel), m_server_thread(st) {}
49
50 virtual void EndWait(KThread* waiting_thread, Result wait_result) override {
51 // Clear the server thread.
52 *m_server_thread = nullptr;
53
54 // Set the waiting thread as not cancelable.
55 waiting_thread->ClearCancellable();
56
57 // Invoke the base end wait handler.
58 KThreadQueue::EndWait(waiting_thread, wait_result);
59 }
60
61 virtual void CancelWait(KThread* waiting_thread, Result wait_result,
62 bool cancel_timer_task) override {
63 // Clear the server thread.
64 *m_server_thread = nullptr;
65
66 // Set the waiting thread as not cancelable.
67 waiting_thread->ClearCancellable();
68
69 // Invoke the base cancel wait handler.
70 KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
71 }
72};
73
74} // namespace
75
76KLightServerSession::KLightServerSession(KernelCore& kernel) : KAutoObject(kernel) {}
77KLightServerSession::~KLightServerSession() = default;
78
79void KLightServerSession::Destroy() {
80 this->CleanupRequests();
81
82 m_parent->OnServerClosed();
83}
84
85void KLightServerSession::OnClientClosed() {
86 this->CleanupRequests();
87}
88
89Result KLightServerSession::OnRequest(KThread* request_thread) {
90 ThreadQueueImplForKLightServerSessionRequest wait_queue(m_kernel,
91 std::addressof(m_request_list));
92
93 // Send the request.
94 {
95 // Lock the scheduler.
96 KScopedSchedulerLock sl(m_kernel);
97
98 // Check that the server isn't closed.
99 R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed);
100
101 // Check that the request thread isn't terminating.
102 R_UNLESS(!request_thread->IsTerminationRequested(), ResultTerminationRequested);
103
104 // Add the request thread to our list.
105 m_request_list.push_back(*request_thread);
106
107 // Begin waiting on the request.
108 request_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
109 request_thread->BeginWait(std::addressof(wait_queue));
110
111 // If we have a server thread, end its wait.
112 if (m_server_thread != nullptr) {
113 m_server_thread->EndWait(ResultSuccess);
114 }
115 }
116
117 // NOTE: Nintendo returns GetCurrentThread().GetWaitResult() here.
118 // This is technically incorrect, although it doesn't cause problems in practice
119 // because this is only ever called with request_thread = GetCurrentThreadPointer().
120 R_RETURN(request_thread->GetWaitResult());
121}
122
123Result KLightServerSession::ReplyAndReceive(u32* data) {
124 // Set the server context.
125 GetCurrentThread(m_kernel).SetLightSessionData(data);
126
127 // Reply, if we need to.
128 if (data[0] & KLightSession::ReplyFlag) {
129 KScopedSchedulerLock sl(m_kernel);
130
131 // Check that we're open.
132 R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed);
133 R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed);
134
135 // Check that we have a request to reply to.
136 R_UNLESS(m_current_request != nullptr, ResultInvalidState);
137
138 // Check that the server thread id is correct.
139 R_UNLESS(m_server_thread_id == GetCurrentThread(m_kernel).GetId(), ResultInvalidState);
140
141 // If we can reply, do so.
142 if (!m_current_request->IsTerminationRequested()) {
143 std::memcpy(m_current_request->GetLightSessionData(),
144 GetCurrentThread(m_kernel).GetLightSessionData(), KLightSession::DataSize);
145 m_current_request->EndWait(ResultSuccess);
146 }
147
148 // Close our current request.
149 m_current_request->Close();
150
151 // Clear our current request.
152 m_current_request = nullptr;
153 m_server_thread_id = InvalidThreadId;
154 }
155
156 // Create the wait queue for our receive.
157 ThreadQueueImplForKLightServerSessionReceive wait_queue(m_kernel,
158 std::addressof(m_server_thread));
159
160 // Receive.
161 while (true) {
162 // Try to receive a request.
163 {
164 KScopedSchedulerLock sl(m_kernel);
165
166 // Check that we aren't already receiving.
167 R_UNLESS(m_server_thread == nullptr, ResultInvalidState);
168 R_UNLESS(m_server_thread_id == InvalidThreadId, ResultInvalidState);
169
170 // Check that we're open.
171 R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed);
172 R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed);
173
174 // Check that we're not terminating.
175 R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(),
176 ResultTerminationRequested);
177
178 // If we have a request available, use it.
179 if (auto head = m_request_list.begin(); head != m_request_list.end()) {
180 // Set our current request.
181 m_current_request = std::addressof(*head);
182 m_current_request->Open();
183
184 // Set our server thread id.
185 m_server_thread_id = GetCurrentThread(m_kernel).GetId();
186
187 // Copy the client request data.
188 std::memcpy(GetCurrentThread(m_kernel).GetLightSessionData(),
189 m_current_request->GetLightSessionData(), KLightSession::DataSize);
190
191 // We successfully received.
192 R_SUCCEED();
193 }
194
195 // We need to wait for a request to come in.
196
197 // Check if we were cancelled.
198 if (GetCurrentThread(m_kernel).IsWaitCancelled()) {
199 GetCurrentThread(m_kernel).ClearWaitCancelled();
200 R_THROW(ResultCancelled);
201 }
202
203 // Mark ourselves as cancellable.
204 GetCurrentThread(m_kernel).SetCancellable();
205
206 // Wait for a request to come in.
207 m_server_thread = GetCurrentThreadPointer(m_kernel);
208 GetCurrentThread(m_kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
209 GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue));
210 }
211
212 // We waited to receive a request; if our wait failed, return the failing result.
213 R_TRY(GetCurrentThread(m_kernel).GetWaitResult());
214 }
215}
216
217void KLightServerSession::CleanupRequests() {
218 // Cleanup all pending requests.
219 {
220 KScopedSchedulerLock sl(m_kernel);
221
222 // Handle the current request.
223 if (m_current_request != nullptr) {
224 // Reply to the current request.
225 if (!m_current_request->IsTerminationRequested()) {
226 m_current_request->EndWait(ResultSessionClosed);
227 }
228
229 // Clear our current request.
230 m_current_request->Close();
231 m_current_request = nullptr;
232 m_server_thread_id = InvalidThreadId;
233 }
234
235 // Reply to all other requests.
236 for (auto& thread : m_request_list) {
237 thread.EndWait(ResultSessionClosed);
238 }
239
240 // Wait up our server thread, if we have one.
241 if (m_server_thread != nullptr) {
242 m_server_thread->EndWait(ResultSessionClosed);
243 }
244 }
245}
246
247} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_server_session.h b/src/core/hle/kernel/k_light_server_session.h
new file mode 100644
index 000000000..8eca3eab6
--- /dev/null
+++ b/src/core/hle/kernel/k_light_server_session.h
@@ -0,0 +1,49 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/kernel/k_auto_object.h"
7#include "core/hle/kernel/k_thread.h"
8#include "core/hle/result.h"
9
10namespace Kernel {
11
12class KLightSession;
13
14class KLightServerSession final : public KAutoObject,
15 public Common::IntrusiveListBaseNode<KLightServerSession> {
16 KERNEL_AUTOOBJECT_TRAITS(KLightServerSession, KAutoObject);
17
18private:
19 KLightSession* m_parent{};
20 KThread::WaiterList m_request_list{};
21 KThread* m_current_request{};
22 u64 m_server_thread_id{std::numeric_limits<u64>::max()};
23 KThread* m_server_thread{};
24
25public:
26 explicit KLightServerSession(KernelCore& kernel);
27 ~KLightServerSession();
28
29 void Initialize(KLightSession* parent) {
30 // Set member variables. */
31 m_parent = parent;
32 }
33
34 virtual void Destroy() override;
35
36 constexpr const KLightSession* GetParent() const {
37 return m_parent;
38 }
39
40 Result OnRequest(KThread* request_thread);
41 Result ReplyAndReceive(u32* data);
42
43 void OnClientClosed();
44
45private:
46 void CleanupRequests();
47};
48
49} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_session.cpp b/src/core/hle/kernel/k_light_session.cpp
new file mode 100644
index 000000000..d8b1e6958
--- /dev/null
+++ b/src/core/hle/kernel/k_light_session.cpp
@@ -0,0 +1,81 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_client_port.h"
5#include "core/hle/kernel/k_light_client_session.h"
6#include "core/hle/kernel/k_light_server_session.h"
7#include "core/hle/kernel/k_light_session.h"
8#include "core/hle/kernel/k_process.h"
9
10namespace Kernel {
11
12KLightSession::KLightSession(KernelCore& kernel)
13 : KAutoObjectWithSlabHeapAndContainer(kernel), m_server(kernel), m_client(kernel) {}
14KLightSession::~KLightSession() = default;
15
16void KLightSession::Initialize(KClientPort* client_port, uintptr_t name) {
17 // Increment reference count.
18 // Because reference count is one on creation, this will result
19 // in a reference count of two. Thus, when both server and client are closed
20 // this object will be destroyed.
21 this->Open();
22
23 // Create our sub sessions.
24 KAutoObject::Create(std::addressof(m_server));
25 KAutoObject::Create(std::addressof(m_client));
26
27 // Initialize our sub sessions.
28 m_server.Initialize(this);
29 m_client.Initialize(this);
30
31 // Set state and name.
32 m_state = State::Normal;
33 m_name = name;
34
35 // Set our owner process.
36 m_process = GetCurrentProcessPointer(m_kernel);
37 m_process->Open();
38
39 // Set our port.
40 m_port = client_port;
41 if (m_port != nullptr) {
42 m_port->Open();
43 }
44
45 // Mark initialized.
46 m_initialized = true;
47}
48
49void KLightSession::Finalize() {
50 if (m_port != nullptr) {
51 m_port->OnSessionFinalized();
52 m_port->Close();
53 }
54}
55
56void KLightSession::OnServerClosed() {
57 if (m_state == State::Normal) {
58 m_state = State::ServerClosed;
59 m_client.OnServerClosed();
60 }
61
62 this->Close();
63}
64
65void KLightSession::OnClientClosed() {
66 if (m_state == State::Normal) {
67 m_state = State::ClientClosed;
68 m_server.OnClientClosed();
69 }
70
71 this->Close();
72}
73
74void KLightSession::PostDestroy(uintptr_t arg) {
75 // Release the session count resource the owner process holds.
76 KProcess* owner = reinterpret_cast<KProcess*>(arg);
77 owner->ReleaseResource(Svc::LimitableResource::SessionCountMax, 1);
78 owner->Close();
79}
80
81} // namespace Kernel
diff --git a/src/core/hle/kernel/k_light_session.h b/src/core/hle/kernel/k_light_session.h
new file mode 100644
index 000000000..f78d8e689
--- /dev/null
+++ b/src/core/hle/kernel/k_light_session.h
@@ -0,0 +1,86 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/kernel/k_light_client_session.h"
7#include "core/hle/kernel/k_light_server_session.h"
8#include "core/hle/kernel/slab_helpers.h"
9#include "core/hle/result.h"
10
11namespace Kernel {
12
13class KClientPort;
14class KProcess;
15
16// TODO: SupportDynamicExpansion for SlabHeap
17class KLightSession final
18 : public KAutoObjectWithSlabHeapAndContainer<KLightSession, KAutoObjectWithList> {
19 KERNEL_AUTOOBJECT_TRAITS(KLightSession, KAutoObject);
20
21private:
22 enum class State : u8 {
23 Invalid = 0,
24 Normal = 1,
25 ClientClosed = 2,
26 ServerClosed = 3,
27 };
28
29public:
30 static constexpr size_t DataSize = sizeof(u32) * 7;
31 static constexpr u32 ReplyFlag = (1U << 31);
32
33private:
34 KLightServerSession m_server;
35 KLightClientSession m_client;
36 State m_state{State::Invalid};
37 KClientPort* m_port{};
38 uintptr_t m_name{};
39 KProcess* m_process{};
40 bool m_initialized{};
41
42public:
43 explicit KLightSession(KernelCore& kernel);
44 ~KLightSession();
45
46 void Initialize(KClientPort* client_port, uintptr_t name);
47 void Finalize() override;
48
49 bool IsInitialized() const override {
50 return m_initialized;
51 }
52 uintptr_t GetPostDestroyArgument() const override {
53 return reinterpret_cast<uintptr_t>(m_process);
54 }
55
56 static void PostDestroy(uintptr_t arg);
57
58 void OnServerClosed();
59 void OnClientClosed();
60
61 bool IsServerClosed() const {
62 return m_state != State::Normal;
63 }
64 bool IsClientClosed() const {
65 return m_state != State::Normal;
66 }
67
68 Result OnRequest(KThread* request_thread) {
69 R_RETURN(m_server.OnRequest(request_thread));
70 }
71
72 KLightClientSession& GetClientSession() {
73 return m_client;
74 }
75 KLightServerSession& GetServerSession() {
76 return m_server;
77 }
78 const KLightClientSession& GetClientSession() const {
79 return m_client;
80 }
81 const KLightServerSession& GetServerSession() const {
82 return m_server;
83 }
84};
85
86} // namespace Kernel
diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp
index 0a973ec8c..d6bd27296 100644
--- a/src/core/hle/kernel/k_memory_manager.cpp
+++ b/src/core/hle/kernel/k_memory_manager.cpp
@@ -421,8 +421,9 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
421 } else { 421 } else {
422 // Set all the allocated memory. 422 // Set all the allocated memory.
423 for (const auto& block : *out) { 423 for (const auto& block : *out) {
424 std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern, 424 m_system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(block.GetAddress()) -
425 block.GetSize()); 425 Core::DramMemoryMap::Base,
426 block.GetSize(), fill_pattern);
426 } 427 }
427 } 428 }
428 429
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp
index 6691586ed..423289145 100644
--- a/src/core/hle/kernel/k_page_table_base.cpp
+++ b/src/core/hle/kernel/k_page_table_base.cpp
@@ -69,8 +69,21 @@ public:
69}; 69};
70 70
71template <typename AddressType> 71template <typename AddressType>
72void InvalidateInstructionCache(Core::System& system, AddressType addr, u64 size) { 72void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 size) {
73 system.InvalidateCpuInstructionCacheRange(GetInteger(addr), size); 73 // TODO: lock the process list
74 for (auto& process : kernel.GetProcessList()) {
75 for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
76 auto* interface = process->GetArmInterface(i);
77 if (interface) {
78 interface->InvalidateCacheRange(GetInteger(addr), size);
79 }
80 }
81 }
82}
83
84void ClearBackingRegion(Core::System& system, KPhysicalAddress addr, u64 size, u32 fill_value) {
85 system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(addr) - Core::DramMemoryMap::Base,
86 size, fill_value);
74} 87}
75 88
76template <typename AddressType> 89template <typename AddressType>
@@ -1261,7 +1274,7 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr
1261 bool reprotected_pages = false; 1274 bool reprotected_pages = false;
1262 SCOPE_EXIT({ 1275 SCOPE_EXIT({
1263 if (reprotected_pages && any_code_pages) { 1276 if (reprotected_pages && any_code_pages) {
1264 InvalidateInstructionCache(m_system, dst_address, size); 1277 InvalidateInstructionCache(m_kernel, dst_address, size);
1265 } 1278 }
1266 }); 1279 });
1267 1280
@@ -1355,8 +1368,7 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) {
1355 1368
1356 // Clear all the newly allocated pages. 1369 // Clear all the newly allocated pages.
1357 for (const auto& it : pg) { 1370 for (const auto& it : pg) {
1358 std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), 1371 ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
1359 static_cast<u32>(m_heap_fill_value), it.GetSize());
1360 } 1372 }
1361 1373
1362 // Lock the table. 1374 // Lock the table.
@@ -1562,8 +1574,7 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce
1562 1574
1563 // Clear all pages. 1575 // Clear all pages.
1564 for (const auto& it : pg) { 1576 for (const auto& it : pg) {
1565 std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), 1577 ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
1566 static_cast<u32>(m_heap_fill_value), it.GetSize());
1567 } 1578 }
1568 1579
1569 // Map the pages. 1580 // Map the pages.
@@ -1997,7 +2008,7 @@ Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t s
1997 for (const auto& block : pg) { 2008 for (const auto& block : pg) {
1998 StoreDataCache(GetHeapVirtualPointer(m_kernel, block.GetAddress()), block.GetSize()); 2009 StoreDataCache(GetHeapVirtualPointer(m_kernel, block.GetAddress()), block.GetSize());
1999 } 2010 }
2000 InvalidateInstructionCache(m_system, addr, size); 2011 InvalidateInstructionCache(m_kernel, addr, size);
2001 } 2012 }
2002 2013
2003 R_SUCCEED(); 2014 R_SUCCEED();
@@ -2151,8 +2162,7 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) {
2151 2162
2152 // Clear all the newly allocated pages. 2163 // Clear all the newly allocated pages.
2153 for (const auto& it : pg) { 2164 for (const auto& it : pg) {
2154 std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), m_heap_fill_value, 2165 ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value);
2155 it.GetSize());
2156 } 2166 }
2157 2167
2158 // Map the pages. 2168 // Map the pages.
@@ -3239,7 +3249,7 @@ Result KPageTableBase::WriteDebugMemory(KProcessAddress dst_address, KProcessAdd
3239 R_TRY(PerformCopy()); 3249 R_TRY(PerformCopy());
3240 3250
3241 // Invalidate the instruction cache, as this svc allows modifying executable pages. 3251 // Invalidate the instruction cache, as this svc allows modifying executable pages.
3242 InvalidateInstructionCache(m_system, dst_address, size); 3252 InvalidateInstructionCache(m_kernel, dst_address, size);
3243 3253
3244 R_SUCCEED(); 3254 R_SUCCEED();
3245} 3255}
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp
index 1621ca1d3..e5f5d8028 100644
--- a/src/core/hle/kernel/k_port.cpp
+++ b/src/core/hle/kernel/k_port.cpp
@@ -58,4 +58,13 @@ Result KPort::EnqueueSession(KServerSession* session) {
58 R_SUCCEED(); 58 R_SUCCEED();
59} 59}
60 60
61Result KPort::EnqueueSession(KLightServerSession* session) {
62 KScopedSchedulerLock sl{m_kernel};
63
64 R_UNLESS(m_state == State::Normal, ResultPortClosed);
65
66 m_server.EnqueueSession(session);
67 R_SUCCEED();
68}
69
61} // namespace Kernel 70} // namespace Kernel
diff --git a/src/core/hle/kernel/k_port.h b/src/core/hle/kernel/k_port.h
index 991be27ab..26f5f14ef 100644
--- a/src/core/hle/kernel/k_port.h
+++ b/src/core/hle/kernel/k_port.h
@@ -13,6 +13,7 @@
13 13
14namespace Kernel { 14namespace Kernel {
15 15
16class KLightServerSession;
16class KServerSession; 17class KServerSession;
17 18
18class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> { 19class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> {
@@ -38,6 +39,7 @@ public:
38 bool IsServerClosed() const; 39 bool IsServerClosed() const;
39 40
40 Result EnqueueSession(KServerSession* session); 41 Result EnqueueSession(KServerSession* session);
42 Result EnqueueSession(KLightServerSession* session);
41 43
42 KClientPort& GetClientPort() { 44 KClientPort& GetClientPort() {
43 return m_client; 45 return m_client;
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 6c29eb72c..3a2635e1f 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -13,6 +13,12 @@
13#include "core/hle/kernel/k_thread_queue.h" 13#include "core/hle/kernel/k_thread_queue.h"
14#include "core/hle/kernel/k_worker_task_manager.h" 14#include "core/hle/kernel/k_worker_task_manager.h"
15 15
16#include "core/arm/dynarmic/arm_dynarmic_32.h"
17#include "core/arm/dynarmic/arm_dynarmic_64.h"
18#ifdef HAS_NCE
19#include "core/arm/nce/arm_nce.h"
20#endif
21
16namespace Kernel { 22namespace Kernel {
17 23
18namespace { 24namespace {
@@ -957,10 +963,8 @@ Result KProcess::Run(s32 priority, size_t stack_size) {
957 R_TRY(m_handle_table.Add(std::addressof(thread_handle), main_thread)); 963 R_TRY(m_handle_table.Add(std::addressof(thread_handle), main_thread));
958 964
959 // Set the thread arguments. 965 // Set the thread arguments.
960 main_thread->GetContext32().cpu_registers[0] = 0; 966 main_thread->GetContext().r[0] = 0;
961 main_thread->GetContext64().cpu_registers[0] = 0; 967 main_thread->GetContext().r[1] = thread_handle;
962 main_thread->GetContext32().cpu_registers[1] = thread_handle;
963 main_thread->GetContext64().cpu_registers[1] = thread_handle;
964 968
965 // Update our state. 969 // Update our state.
966 this->ChangeState((state == State::Created) ? State::Running : State::RunningAttached); 970 this->ChangeState((state == State::Created) ? State::Running : State::RunningAttached);
@@ -1199,6 +1203,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
1199 m_is_hbl = is_hbl; 1203 m_is_hbl = is_hbl;
1200 m_ideal_core_id = metadata.GetMainThreadCore(); 1204 m_ideal_core_id = metadata.GetMainThreadCore();
1201 1205
1206 // Set up emulation context.
1207 this->InitializeInterfaces();
1208
1202 // We succeeded. 1209 // We succeeded.
1203 R_SUCCEED(); 1210 R_SUCCEED();
1204} 1211}
@@ -1227,6 +1234,31 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
1227#endif 1234#endif
1228} 1235}
1229 1236
1237void KProcess::InitializeInterfaces() {
1238 this->GetMemory().SetCurrentPageTable(*this);
1239
1240#ifdef HAS_NCE
1241 if (this->Is64Bit() && Settings::IsNceEnabled()) {
1242 for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
1243 m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
1244 }
1245 } else
1246#endif
1247 if (this->Is64Bit()) {
1248 for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
1249 m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>(
1250 m_kernel.System(), m_kernel.IsMulticore(), this,
1251 static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
1252 }
1253 } else {
1254 for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
1255 m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>(
1256 m_kernel.System(), m_kernel.IsMulticore(), this,
1257 static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i);
1258 }
1259 }
1260}
1261
1230bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) { 1262bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) {
1231 const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) { 1263 const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) {
1232 return wp.type == DebugWatchpointType::None; 1264 return wp.type == DebugWatchpointType::None;
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index d8cd0fdde..4b114e39b 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -5,6 +5,7 @@
5 5
6#include <map> 6#include <map>
7 7
8#include "core/arm/arm_interface.h"
8#include "core/file_sys/program_metadata.h" 9#include "core/file_sys/program_metadata.h"
9#include "core/hle/kernel/code_set.h" 10#include "core/hle/kernel/code_set.h"
10#include "core/hle/kernel/k_address_arbiter.h" 11#include "core/hle/kernel/k_address_arbiter.h"
@@ -106,6 +107,8 @@ private:
106 bool m_is_suspended{}; 107 bool m_is_suspended{};
107 bool m_is_immortal{}; 108 bool m_is_immortal{};
108 bool m_is_handle_table_initialized{}; 109 bool m_is_handle_table_initialized{};
110 std::array<std::unique_ptr<Core::ArmInterface>, Core::Hardware::NUM_CPU_CORES>
111 m_arm_interfaces{};
109 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_running_threads{}; 112 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_running_threads{};
110 std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_idle_counts{}; 113 std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_idle_counts{};
111 std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_switch_counts{}; 114 std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_switch_counts{};
@@ -476,6 +479,10 @@ public:
476 } 479 }
477#endif 480#endif
478 481
482 Core::ArmInterface* GetArmInterface(size_t core_index) const {
483 return m_arm_interfaces[core_index].get();
484 }
485
479public: 486public:
480 // Attempts to insert a watchpoint into a free slot. Returns false if none are available. 487 // Attempts to insert a watchpoint into a free slot. Returns false if none are available.
481 bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); 488 bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type);
@@ -493,6 +500,8 @@ public:
493 500
494 void LoadModule(CodeSet code_set, KProcessAddress base_addr); 501 void LoadModule(CodeSet code_set, KProcessAddress base_addr);
495 502
503 void InitializeInterfaces();
504
496 Core::Memory::Memory& GetMemory() const; 505 Core::Memory::Memory& GetMemory() const;
497 506
498public: 507public:
diff --git a/src/core/hle/kernel/k_process_page_table.h b/src/core/hle/kernel/k_process_page_table.h
index 9e40f68bc..346d7ca08 100644
--- a/src/core/hle/kernel/k_process_page_table.h
+++ b/src/core/hle/kernel/k_process_page_table.h
@@ -7,10 +7,6 @@
7#include "core/hle/kernel/k_scoped_lock.h" 7#include "core/hle/kernel/k_scoped_lock.h"
8#include "core/hle/kernel/svc_types.h" 8#include "core/hle/kernel/svc_types.h"
9 9
10namespace Core {
11class ARM_Interface;
12}
13
14namespace Kernel { 10namespace Kernel {
15 11
16class KProcessPageTable { 12class KProcessPageTable {
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 1bce63a56..27d1c3846 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -494,12 +494,7 @@ void KScheduler::ScheduleImplFiber() {
494} 494}
495 495
496void KScheduler::Unload(KThread* thread) { 496void KScheduler::Unload(KThread* thread) {
497 auto& cpu_core = m_kernel.System().ArmInterface(m_core_id); 497 m_kernel.PhysicalCore(m_core_id).SaveContext(thread);
498 cpu_core.SaveContext(thread->GetContext32());
499 cpu_core.SaveContext(thread->GetContext64());
500 // Save the TPIDR_EL0 system register in case it was modified.
501 thread->SetTpidrEl0(cpu_core.GetTPIDR_EL0());
502 cpu_core.ClearExclusiveState();
503 498
504 // Check if the thread is terminated by checking the DPC flags. 499 // Check if the thread is terminated by checking the DPC flags.
505 if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) { 500 if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) {
@@ -509,14 +504,7 @@ void KScheduler::Unload(KThread* thread) {
509} 504}
510 505
511void KScheduler::Reload(KThread* thread) { 506void KScheduler::Reload(KThread* thread) {
512 auto& cpu_core = m_kernel.System().ArmInterface(m_core_id); 507 m_kernel.PhysicalCore(m_core_id).LoadContext(thread);
513 auto* process = thread->GetOwnerProcess();
514 cpu_core.LoadContext(thread->GetContext32());
515 cpu_core.LoadContext(thread->GetContext64());
516 cpu_core.SetTlsAddress(GetInteger(thread->GetTlsAddress()));
517 cpu_core.SetTPIDR_EL0(thread->GetTpidrEl0());
518 cpu_core.LoadWatchpointArray(process ? &process->GetWatchpoints() : nullptr);
519 cpu_core.ClearExclusiveState();
520} 508}
521 509
522void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) { 510void KScheduler::ClearPreviousThread(KernelCore& kernel, KThread* thread) {
diff --git a/src/core/hle/kernel/k_server_port.cpp b/src/core/hle/kernel/k_server_port.cpp
index a29d34bc1..bb6632f58 100644
--- a/src/core/hle/kernel/k_server_port.cpp
+++ b/src/core/hle/kernel/k_server_port.cpp
@@ -27,12 +27,14 @@ bool KServerPort::IsLight() const {
27void KServerPort::CleanupSessions() { 27void KServerPort::CleanupSessions() {
28 // Ensure our preconditions are met. 28 // Ensure our preconditions are met.
29 if (this->IsLight()) { 29 if (this->IsLight()) {
30 UNIMPLEMENTED(); 30 ASSERT(m_session_list.empty());
31 } else {
32 ASSERT(m_light_session_list.empty());
31 } 33 }
32 34
33 // Cleanup the session list. 35 // Cleanup the session list.
34 while (true) { 36 while (true) {
35 // Get the last session in the list 37 // Get the last session in the list.
36 KServerSession* session = nullptr; 38 KServerSession* session = nullptr;
37 { 39 {
38 KScopedSchedulerLock sl{m_kernel}; 40 KScopedSchedulerLock sl{m_kernel};
@@ -49,6 +51,26 @@ void KServerPort::CleanupSessions() {
49 break; 51 break;
50 } 52 }
51 } 53 }
54
55 // Cleanup the light session list.
56 while (true) {
57 // Get the last session in the list.
58 KLightServerSession* session = nullptr;
59 {
60 KScopedSchedulerLock sl{m_kernel};
61 if (!m_light_session_list.empty()) {
62 session = std::addressof(m_light_session_list.front());
63 m_light_session_list.pop_front();
64 }
65 }
66
67 // Close the session.
68 if (session != nullptr) {
69 session->Close();
70 } else {
71 break;
72 }
73 }
52} 74}
53 75
54void KServerPort::Destroy() { 76void KServerPort::Destroy() {
@@ -64,8 +86,7 @@ void KServerPort::Destroy() {
64 86
65bool KServerPort::IsSignaled() const { 87bool KServerPort::IsSignaled() const {
66 if (this->IsLight()) { 88 if (this->IsLight()) {
67 UNIMPLEMENTED(); 89 return !m_light_session_list.empty();
68 return false;
69 } else { 90 } else {
70 return !m_session_list.empty(); 91 return !m_session_list.empty();
71 } 92 }
@@ -83,6 +104,18 @@ void KServerPort::EnqueueSession(KServerSession* session) {
83 } 104 }
84} 105}
85 106
107void KServerPort::EnqueueSession(KLightServerSession* session) {
108 ASSERT(this->IsLight());
109
110 KScopedSchedulerLock sl{m_kernel};
111
112 // Add the session to our queue.
113 m_light_session_list.push_back(*session);
114 if (m_light_session_list.size() == 1) {
115 this->NotifyAvailable();
116 }
117}
118
86KServerSession* KServerPort::AcceptSession() { 119KServerSession* KServerPort::AcceptSession() {
87 ASSERT(!this->IsLight()); 120 ASSERT(!this->IsLight());
88 121
@@ -98,4 +131,19 @@ KServerSession* KServerPort::AcceptSession() {
98 return session; 131 return session;
99} 132}
100 133
134KLightServerSession* KServerPort::AcceptLightSession() {
135 ASSERT(this->IsLight());
136
137 KScopedSchedulerLock sl{m_kernel};
138
139 // Return the first session in the list.
140 if (m_light_session_list.empty()) {
141 return nullptr;
142 }
143
144 KLightServerSession* session = std::addressof(m_light_session_list.front());
145 m_light_session_list.pop_front();
146 return session;
147}
148
101} // namespace Kernel 149} // namespace Kernel
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h
index 625280290..72fdb6734 100644
--- a/src/core/hle/kernel/k_server_port.h
+++ b/src/core/hle/kernel/k_server_port.h
@@ -9,6 +9,7 @@
9 9
10#include "common/intrusive_list.h" 10#include "common/intrusive_list.h"
11 11
12#include "core/hle/kernel/k_light_server_session.h"
12#include "core/hle/kernel/k_server_session.h" 13#include "core/hle/kernel/k_server_session.h"
13#include "core/hle/kernel/k_synchronization_object.h" 14#include "core/hle/kernel/k_synchronization_object.h"
14 15
@@ -28,8 +29,10 @@ public:
28 void Initialize(KPort* parent); 29 void Initialize(KPort* parent);
29 30
30 void EnqueueSession(KServerSession* session); 31 void EnqueueSession(KServerSession* session);
32 void EnqueueSession(KLightServerSession* session);
31 33
32 KServerSession* AcceptSession(); 34 KServerSession* AcceptSession();
35 KLightServerSession* AcceptLightSession();
33 36
34 const KPort* GetParent() const { 37 const KPort* GetParent() const {
35 return m_parent; 38 return m_parent;
@@ -43,10 +46,12 @@ public:
43 46
44private: 47private:
45 using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType; 48 using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType;
49 using LightSessionList = Common::IntrusiveListBaseTraits<KLightServerSession>::ListType;
46 50
47 void CleanupSessions(); 51 void CleanupSessions();
48 52
49 SessionList m_session_list{}; 53 SessionList m_session_list{};
54 LightSessionList m_light_session_list{};
50 KPort* m_parent{}; 55 KPort* m_parent{};
51}; 56};
52 57
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 3ea653163..e33a88e24 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -453,6 +453,11 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
453 size_t client_buffer_size = request->GetSize(); 453 size_t client_buffer_size = request->GetSize();
454 // bool recv_list_broken = false; 454 // bool recv_list_broken = false;
455 455
456 if (!client_message) {
457 client_message = GetInteger(client_thread->GetTlsAddress());
458 client_buffer_size = MessageBufferSize;
459 }
460
456 // Receive the message. 461 // Receive the message.
457 Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; 462 Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()};
458 if (out_context != nullptr) { 463 if (out_context != nullptr) {
@@ -462,8 +467,7 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext
462 std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread); 467 std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread);
463 (*out_context)->SetSessionRequestManager(manager); 468 (*out_context)->SetSessionRequestManager(manager);
464 (*out_context) 469 (*out_context)
465 ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), 470 ->PopulateFromIncomingCommandBuffer(*client_thread->GetOwnerProcess(), cmd_buf);
466 cmd_buf);
467 } else { 471 } else {
468 KThread* server_thread = GetCurrentThreadPointer(m_kernel); 472 KThread* server_thread = GetCurrentThreadPointer(m_kernel);
469 KProcess& src_process = *client_thread->GetOwnerProcess(); 473 KProcess& src_process = *client_thread->GetOwnerProcess();
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h
index f69bab088..3f4dd5989 100644
--- a/src/core/hle/kernel/k_session.h
+++ b/src/core/hle/kernel/k_session.h
@@ -46,6 +46,10 @@ public:
46 return this->GetState() != State::Normal; 46 return this->GetState() != State::Normal;
47 } 47 }
48 48
49 Result OnRequest(KSessionRequest* request) {
50 R_RETURN(m_server.OnRequest(request));
51 }
52
49 KClientSession& GetClientSession() { 53 KClientSession& GetClientSession() {
50 return m_client; 54 return m_client;
51 } 55 }
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index a6deb50ec..7d9a6e9cf 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -41,24 +41,25 @@ namespace {
41 41
42constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1; 42constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1;
43 43
44static void ResetThreadContext32(Kernel::KThread::ThreadContext32& context, u32 stack_top, 44static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point,
45 u32 entry_point, u32 arg) { 45 u64 arg) {
46 context = {}; 46 ctx = {};
47 context.cpu_registers[0] = arg; 47 ctx.r[0] = arg;
48 context.cpu_registers[15] = entry_point; 48 ctx.r[15] = entry_point;
49 context.cpu_registers[13] = stack_top; 49 ctx.r[13] = stack_top;
50 context.fpscr = 0; 50 ctx.fpcr = 0;
51} 51 ctx.fpsr = 0;
52 52}
53static void ResetThreadContext64(Kernel::KThread::ThreadContext64& context, u64 stack_top, 53
54 u64 entry_point, u64 arg) { 54static void ResetThreadContext64(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point,
55 context = {}; 55 u64 arg) {
56 context.cpu_registers[0] = arg; 56 ctx = {};
57 context.cpu_registers[18] = Kernel::KSystemControl::GenerateRandomU64() | 1; 57 ctx.r[0] = arg;
58 context.pc = entry_point; 58 ctx.r[18] = Kernel::KSystemControl::GenerateRandomU64() | 1;
59 context.sp = stack_top; 59 ctx.pc = entry_point;
60 context.fpcr = 0; 60 ctx.sp = stack_top;
61 context.fpsr = 0; 61 ctx.fpcr = 0;
62 ctx.fpsr = 0;
62} 63}
63} // namespace 64} // namespace
64 65
@@ -223,9 +224,11 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, KProcessAddress
223 } 224 }
224 225
225 // Initialize thread context. 226 // Initialize thread context.
226 ResetThreadContext64(m_thread_context_64, GetInteger(user_stack_top), GetInteger(func), arg); 227 if (m_parent != nullptr && !m_parent->Is64Bit()) {
227 ResetThreadContext32(m_thread_context_32, static_cast<u32>(GetInteger(user_stack_top)), 228 ResetThreadContext32(m_thread_context, GetInteger(user_stack_top), GetInteger(func), arg);
228 static_cast<u32>(GetInteger(func)), static_cast<u32>(arg)); 229 } else {
230 ResetThreadContext64(m_thread_context, GetInteger(user_stack_top), GetInteger(func), arg);
231 }
229 232
230 // Setup the stack parameters. 233 // Setup the stack parameters.
231 StackParameters& sp = this->GetStackParameters(); 234 StackParameters& sp = this->GetStackParameters();
@@ -823,20 +826,7 @@ void KThread::CloneFpuStatus() {
823 ASSERT(this->GetOwnerProcess() != nullptr); 826 ASSERT(this->GetOwnerProcess() != nullptr);
824 ASSERT(this->GetOwnerProcess() == GetCurrentProcessPointer(m_kernel)); 827 ASSERT(this->GetOwnerProcess() == GetCurrentProcessPointer(m_kernel));
825 828
826 if (this->GetOwnerProcess()->Is64Bit()) { 829 m_kernel.CurrentPhysicalCore().CloneFpuStatus(this);
827 // Clone FPSR and FPCR.
828 ThreadContext64 cur_ctx{};
829 m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx);
830
831 this->GetContext64().fpcr = cur_ctx.fpcr;
832 this->GetContext64().fpsr = cur_ctx.fpsr;
833 } else {
834 // Clone FPSCR.
835 ThreadContext32 cur_ctx{};
836 m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx);
837
838 this->GetContext32().fpscr = cur_ctx.fpscr;
839 }
840} 830}
841 831
842Result KThread::SetActivity(Svc::ThreadActivity activity) { 832Result KThread::SetActivity(Svc::ThreadActivity activity) {
@@ -912,7 +902,7 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) {
912 R_SUCCEED(); 902 R_SUCCEED();
913} 903}
914 904
915Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) { 905Result KThread::GetThreadContext3(Svc::ThreadContext* out) {
916 // Lock ourselves. 906 // Lock ourselves.
917 KScopedLightLock lk{m_activity_pause_lock}; 907 KScopedLightLock lk{m_activity_pause_lock};
918 908
@@ -926,18 +916,16 @@ Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) {
926 916
927 // If we're not terminating, get the thread's user context. 917 // If we're not terminating, get the thread's user context.
928 if (!this->IsTerminationRequested()) { 918 if (!this->IsTerminationRequested()) {
919 *out = m_thread_context;
920
921 // Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
922 constexpr u32 El0Aarch64PsrMask = 0xF0000000;
923 constexpr u32 El0Aarch32PsrMask = 0xFE0FFE20;
924
929 if (m_parent->Is64Bit()) { 925 if (m_parent->Is64Bit()) {
930 // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. 926 out->pstate &= El0Aarch64PsrMask;
931 auto context = GetContext64();
932 context.pstate &= 0xFF0FFE20;
933 out.resize_destructive(sizeof(context));
934 std::memcpy(out.data(), std::addressof(context), sizeof(context));
935 } else { 927 } else {
936 // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. 928 out->pstate &= El0Aarch32PsrMask;
937 auto context = GetContext32();
938 context.cpsr &= 0xFF0FFE20;
939 out.resize_destructive(sizeof(context));
940 std::memcpy(out.data(), std::addressof(context), sizeof(context));
941 } 929 }
942 } 930 }
943 } 931 }
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index e9ca5dfca..e9925d231 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -38,7 +38,6 @@ namespace Core {
38namespace Memory { 38namespace Memory {
39class Memory; 39class Memory;
40} 40}
41class ARM_Interface;
42class System; 41class System;
43} // namespace Core 42} // namespace Core
44 43
@@ -137,8 +136,6 @@ public:
137 ~KThread() override; 136 ~KThread() override;
138 137
139public: 138public:
140 using ThreadContext32 = Core::ARM_Interface::ThreadContext32;
141 using ThreadContext64 = Core::ARM_Interface::ThreadContext64;
142 using WaiterList = Common::IntrusiveListBaseTraits<KThread>::ListType; 139 using WaiterList = Common::IntrusiveListBaseTraits<KThread>::ListType;
143 140
144 /** 141 /**
@@ -246,31 +243,22 @@ public:
246 * @returns The value of the TPIDR_EL0 register. 243 * @returns The value of the TPIDR_EL0 register.
247 */ 244 */
248 u64 GetTpidrEl0() const { 245 u64 GetTpidrEl0() const {
249 return m_thread_context_64.tpidr; 246 return m_thread_context.tpidr;
250 } 247 }
251 248
252 /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread. 249 /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread.
253 void SetTpidrEl0(u64 value) { 250 void SetTpidrEl0(u64 value) {
254 m_thread_context_64.tpidr = value; 251 m_thread_context.tpidr = value;
255 m_thread_context_32.tpidr = static_cast<u32>(value);
256 } 252 }
257 253
258 void CloneFpuStatus(); 254 void CloneFpuStatus();
259 255
260 ThreadContext32& GetContext32() { 256 Svc::ThreadContext& GetContext() {
261 return m_thread_context_32; 257 return m_thread_context;
262 } 258 }
263 259
264 const ThreadContext32& GetContext32() const { 260 const Svc::ThreadContext& GetContext() const {
265 return m_thread_context_32; 261 return m_thread_context;
266 }
267
268 ThreadContext64& GetContext64() {
269 return m_thread_context_64;
270 }
271
272 const ThreadContext64& GetContext64() const {
273 return m_thread_context_64;
274 } 262 }
275 263
276 std::shared_ptr<Common::Fiber>& GetHostContext(); 264 std::shared_ptr<Common::Fiber>& GetHostContext();
@@ -397,6 +385,13 @@ public:
397 m_cancellable = false; 385 m_cancellable = false;
398 } 386 }
399 387
388 u32* GetLightSessionData() const {
389 return m_light_ipc_data;
390 }
391 void SetLightSessionData(u32* data) {
392 m_light_ipc_data = data;
393 }
394
400 bool IsTerminationRequested() const { 395 bool IsTerminationRequested() const {
401 return m_termination_requested || GetRawState() == ThreadState::Terminated; 396 return m_termination_requested || GetRawState() == ThreadState::Terminated;
402 } 397 }
@@ -577,7 +572,7 @@ public:
577 572
578 void RemoveWaiter(KThread* thread); 573 void RemoveWaiter(KThread* thread);
579 574
580 Result GetThreadContext3(Common::ScratchBuffer<u8>& out); 575 Result GetThreadContext3(Svc::ThreadContext* out);
581 576
582 KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) { 577 KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) {
583 return this->RemoveWaiterByKey(out_has_waiters, key, false); 578 return this->RemoveWaiterByKey(out_has_waiters, key, false);
@@ -734,8 +729,7 @@ private:
734 std::function<void()>&& init_func); 729 std::function<void()>&& init_func);
735 730
736 // For core KThread implementation 731 // For core KThread implementation
737 ThreadContext32 m_thread_context_32{}; 732 Svc::ThreadContext m_thread_context{};
738 ThreadContext64 m_thread_context_64{};
739 Common::IntrusiveListNode m_process_list_node; 733 Common::IntrusiveListNode m_process_list_node;
740 Common::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{}; 734 Common::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{};
741 s32 m_priority{}; 735 s32 m_priority{};
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4a1559291..e479dacde 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -99,13 +99,6 @@ struct KernelCore::Impl {
99 RegisterHostThread(nullptr); 99 RegisterHostThread(nullptr);
100 } 100 }
101 101
102 void InitializeCores() {
103 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
104 cores[core_id]->Initialize((*application_process).Is64Bit());
105 system.ApplicationMemory().SetCurrentPageTable(*application_process, core_id);
106 }
107 }
108
109 void TerminateApplicationProcess() { 102 void TerminateApplicationProcess() {
110 application_process.load()->Terminate(); 103 application_process.load()->Terminate();
111 } 104 }
@@ -142,7 +135,6 @@ struct KernelCore::Impl {
142 obj = nullptr; 135 obj = nullptr;
143 } 136 }
144 }; 137 };
145 CleanupObject(hid_shared_mem);
146 CleanupObject(font_shared_mem); 138 CleanupObject(font_shared_mem);
147 CleanupObject(irs_shared_mem); 139 CleanupObject(irs_shared_mem);
148 CleanupObject(time_shared_mem); 140 CleanupObject(time_shared_mem);
@@ -205,7 +197,7 @@ struct KernelCore::Impl {
205 const s32 core{static_cast<s32>(i)}; 197 const s32 core{static_cast<s32>(i)};
206 198
207 schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel()); 199 schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel());
208 cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]); 200 cores[i] = std::make_unique<Kernel::PhysicalCore>(system.Kernel(), i);
209 201
210 auto* main_thread{Kernel::KThread::Create(system.Kernel())}; 202 auto* main_thread{Kernel::KThread::Create(system.Kernel())};
211 main_thread->SetCurrentCore(core); 203 main_thread->SetCurrentCore(core);
@@ -751,22 +743,16 @@ struct KernelCore::Impl {
751 void InitializeHackSharedMemory(KernelCore& kernel) { 743 void InitializeHackSharedMemory(KernelCore& kernel) {
752 // Setup memory regions for emulated processes 744 // Setup memory regions for emulated processes
753 // TODO(bunnei): These should not be hardcoded regions initialized within the kernel 745 // TODO(bunnei): These should not be hardcoded regions initialized within the kernel
754 constexpr std::size_t hid_size{0x40000};
755 constexpr std::size_t font_size{0x1100000}; 746 constexpr std::size_t font_size{0x1100000};
756 constexpr std::size_t irs_size{0x8000}; 747 constexpr std::size_t irs_size{0x8000};
757 constexpr std::size_t time_size{0x1000}; 748 constexpr std::size_t time_size{0x1000};
758 constexpr std::size_t hidbus_size{0x1000}; 749 constexpr std::size_t hidbus_size{0x1000};
759 750
760 hid_shared_mem = KSharedMemory::Create(system.Kernel());
761 font_shared_mem = KSharedMemory::Create(system.Kernel()); 751 font_shared_mem = KSharedMemory::Create(system.Kernel());
762 irs_shared_mem = KSharedMemory::Create(system.Kernel()); 752 irs_shared_mem = KSharedMemory::Create(system.Kernel());
763 time_shared_mem = KSharedMemory::Create(system.Kernel()); 753 time_shared_mem = KSharedMemory::Create(system.Kernel());
764 hidbus_shared_mem = KSharedMemory::Create(system.Kernel()); 754 hidbus_shared_mem = KSharedMemory::Create(system.Kernel());
765 755
766 hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
767 Svc::MemoryPermission::Read, hid_size);
768 KSharedMemory::Register(kernel, hid_shared_mem);
769
770 font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, 756 font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None,
771 Svc::MemoryPermission::Read, font_size); 757 Svc::MemoryPermission::Read, font_size);
772 KSharedMemory::Register(kernel, font_shared_mem); 758 KSharedMemory::Register(kernel, font_shared_mem);
@@ -880,10 +866,6 @@ void KernelCore::Initialize() {
880 impl->Initialize(*this); 866 impl->Initialize(*this);
881} 867}
882 868
883void KernelCore::InitializeCores() {
884 impl->InitializeCores();
885}
886
887void KernelCore::Shutdown() { 869void KernelCore::Shutdown() {
888 impl->Shutdown(); 870 impl->Shutdown();
889} 871}
@@ -993,21 +975,6 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
993 return *impl->global_object_list_container; 975 return *impl->global_object_list_container;
994} 976}
995 977
996void KernelCore::InvalidateAllInstructionCaches() {
997 for (auto& physical_core : impl->cores) {
998 physical_core->ArmInterface().ClearInstructionCache();
999 }
1000}
1001
1002void KernelCore::InvalidateCpuInstructionCacheRange(KProcessAddress addr, std::size_t size) {
1003 for (auto& physical_core : impl->cores) {
1004 if (!physical_core->IsInitialized()) {
1005 continue;
1006 }
1007 physical_core->ArmInterface().InvalidateCacheRange(GetInteger(addr), size);
1008 }
1009}
1010
1011void KernelCore::PrepareReschedule(std::size_t id) { 978void KernelCore::PrepareReschedule(std::size_t id) {
1012 // TODO: Reimplement, this 979 // TODO: Reimplement, this
1013} 980}
@@ -1216,14 +1183,6 @@ const KSystemResource& KernelCore::GetSystemSystemResource() const {
1216 return *impl->sys_system_resource; 1183 return *impl->sys_system_resource;
1217} 1184}
1218 1185
1219Kernel::KSharedMemory& KernelCore::GetHidSharedMem() {
1220 return *impl->hid_shared_mem;
1221}
1222
1223const Kernel::KSharedMemory& KernelCore::GetHidSharedMem() const {
1224 return *impl->hid_shared_mem;
1225}
1226
1227Kernel::KSharedMemory& KernelCore::GetFontSharedMem() { 1186Kernel::KSharedMemory& KernelCore::GetFontSharedMem() {
1228 return *impl->font_shared_mem; 1187 return *impl->font_shared_mem;
1229} 1188}
@@ -1366,6 +1325,7 @@ struct KernelCore::SlabHeapContainer {
1366 KSlabHeap<KProcess> process; 1325 KSlabHeap<KProcess> process;
1367 KSlabHeap<KResourceLimit> resource_limit; 1326 KSlabHeap<KResourceLimit> resource_limit;
1368 KSlabHeap<KSession> session; 1327 KSlabHeap<KSession> session;
1328 KSlabHeap<KLightSession> light_session;
1369 KSlabHeap<KSharedMemory> shared_memory; 1329 KSlabHeap<KSharedMemory> shared_memory;
1370 KSlabHeap<KSharedMemoryInfo> shared_memory_info; 1330 KSlabHeap<KSharedMemoryInfo> shared_memory_info;
1371 KSlabHeap<KThread> thread; 1331 KSlabHeap<KThread> thread;
@@ -1396,6 +1356,8 @@ KSlabHeap<T>& KernelCore::SlabHeap() {
1396 return slab_heap_container->resource_limit; 1356 return slab_heap_container->resource_limit;
1397 } else if constexpr (std::is_same_v<T, KSession>) { 1357 } else if constexpr (std::is_same_v<T, KSession>) {
1398 return slab_heap_container->session; 1358 return slab_heap_container->session;
1359 } else if constexpr (std::is_same_v<T, KLightSession>) {
1360 return slab_heap_container->light_session;
1399 } else if constexpr (std::is_same_v<T, KSharedMemory>) { 1361 } else if constexpr (std::is_same_v<T, KSharedMemory>) {
1400 return slab_heap_container->shared_memory; 1362 return slab_heap_container->shared_memory;
1401 } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) { 1363 } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) {
@@ -1433,6 +1395,7 @@ template KSlabHeap<KPort>& KernelCore::SlabHeap();
1433template KSlabHeap<KProcess>& KernelCore::SlabHeap(); 1395template KSlabHeap<KProcess>& KernelCore::SlabHeap();
1434template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap(); 1396template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap();
1435template KSlabHeap<KSession>& KernelCore::SlabHeap(); 1397template KSlabHeap<KSession>& KernelCore::SlabHeap();
1398template KSlabHeap<KLightSession>& KernelCore::SlabHeap();
1436template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap(); 1399template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap();
1437template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap(); 1400template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap();
1438template KSlabHeap<KThread>& KernelCore::SlabHeap(); 1401template KSlabHeap<KThread>& KernelCore::SlabHeap();
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index d8086c0ea..78c88902c 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -104,9 +104,6 @@ public:
104 /// Resets the kernel to a clean slate for use. 104 /// Resets the kernel to a clean slate for use.
105 void Initialize(); 105 void Initialize();
106 106
107 /// Initializes the CPU cores.
108 void InitializeCores();
109
110 /// Clears all resources in use by the kernel instance. 107 /// Clears all resources in use by the kernel instance.
111 void Shutdown(); 108 void Shutdown();
112 109
@@ -181,10 +178,6 @@ public:
181 178
182 const KAutoObjectWithListContainer& ObjectListContainer() const; 179 const KAutoObjectWithListContainer& ObjectListContainer() const;
183 180
184 void InvalidateAllInstructionCaches();
185
186 void InvalidateCpuInstructionCacheRange(KProcessAddress addr, std::size_t size);
187
188 /// Registers all kernel objects with the global emulation state, this is purely for tracking 181 /// Registers all kernel objects with the global emulation state, this is purely for tracking
189 /// leaks after emulation has been shutdown. 182 /// leaks after emulation has been shutdown.
190 void RegisterKernelObject(KAutoObject* object); 183 void RegisterKernelObject(KAutoObject* object);
@@ -246,12 +239,6 @@ public:
246 /// Gets the system resource manager. 239 /// Gets the system resource manager.
247 const KSystemResource& GetSystemSystemResource() const; 240 const KSystemResource& GetSystemSystemResource() const;
248 241
249 /// Gets the shared memory object for HID services.
250 Kernel::KSharedMemory& GetHidSharedMem();
251
252 /// Gets the shared memory object for HID services.
253 const Kernel::KSharedMemory& GetHidSharedMem() const;
254
255 /// Gets the shared memory object for font services. 242 /// Gets the shared memory object for font services.
256 Kernel::KSharedMemory& GetFontSharedMem(); 243 Kernel::KSharedMemory& GetFontSharedMem();
257 244
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 073039825..0f45a3249 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -1,62 +1,206 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 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 "common/settings.h" 5#include "common/settings.h"
5#include "core/arm/dynarmic/arm_dynarmic_32.h"
6#include "core/arm/dynarmic/arm_dynarmic_64.h"
7#ifdef HAS_NCE
8#include "core/arm/nce/arm_nce.h"
9#endif
10#include "core/core.h" 6#include "core/core.h"
11#include "core/hle/kernel/k_scheduler.h" 7#include "core/debugger/debugger.h"
8#include "core/hle/kernel/k_process.h"
9#include "core/hle/kernel/k_thread.h"
12#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/physical_core.h" 11#include "core/hle/kernel/physical_core.h"
12#include "core/hle/kernel/svc.h"
14 13
15namespace Kernel { 14namespace Kernel {
16 15
17PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KScheduler& scheduler) 16PhysicalCore::PhysicalCore(KernelCore& kernel, std::size_t core_index)
18 : m_core_index{core_index}, m_system{system}, m_scheduler{scheduler} { 17 : m_kernel{kernel}, m_core_index{core_index} {
19#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) 18 m_is_single_core = !kernel.IsMulticore();
20 // TODO(bunnei): Initialization relies on a core being available. We may later replace this with
21 // an NCE interface or a 32-bit instance of Dynarmic. This should be abstracted out to a CPU
22 // manager.
23 auto& kernel = system.Kernel();
24 m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
25 system, kernel.IsMulticore(),
26 reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()),
27 m_core_index);
28#else
29#error Platform not supported yet.
30#endif
31} 19}
32
33PhysicalCore::~PhysicalCore() = default; 20PhysicalCore::~PhysicalCore() = default;
34 21
35void PhysicalCore::Initialize(bool is_64_bit) { 22void PhysicalCore::RunThread(Kernel::KThread* thread) {
36#if defined(HAS_NCE) 23 auto* process = thread->GetOwnerProcess();
37 if (Settings::IsNceEnabled()) { 24 auto& system = m_kernel.System();
38 m_arm_interface = std::make_unique<Core::ARM_NCE>(m_system, m_system.Kernel().IsMulticore(), 25 auto* interface = process->GetArmInterface(m_core_index);
39 m_core_index); 26
27 interface->Initialize();
28
29 const auto EnterContext = [&]() {
30 system.EnterCPUProfile();
31
32 // Lock the core context.
33 std::scoped_lock lk{m_guard};
34
35 // Check if we are already interrupted. If we are, we can just stop immediately.
36 if (m_is_interrupted) {
37 return false;
38 }
39
40 // Mark that we are running.
41 m_arm_interface = interface;
42 m_current_thread = thread;
43
44 // Acquire the lock on the thread parameters.
45 // This allows us to force synchronization with Interrupt.
46 interface->LockThread(thread);
47
48 return true;
49 };
50
51 const auto ExitContext = [&]() {
52 // Unlock the thread.
53 interface->UnlockThread(thread);
54
55 // Lock the core context.
56 std::scoped_lock lk{m_guard};
57
58 // On exit, we no longer are running.
59 m_arm_interface = nullptr;
60 m_current_thread = nullptr;
61
62 system.ExitCPUProfile();
63 };
64
65 while (true) {
66 // If the thread is scheduled for termination, exit.
67 if (thread->HasDpc() && thread->IsTerminationRequested()) {
68 thread->Exit();
69 }
70
71 // Notify the debugger and go to sleep if a step was performed
72 // and this thread has been scheduled again.
73 if (thread->GetStepState() == StepState::StepPerformed) {
74 system.GetDebugger().NotifyThreadStopped(thread);
75 thread->RequestSuspend(SuspendType::Debug);
76 return;
77 }
78
79 // Otherwise, run the thread.
80 Core::HaltReason hr{};
81 {
82 // If we were interrupted, exit immediately.
83 if (!EnterContext()) {
84 return;
85 }
86
87 if (thread->GetStepState() == StepState::StepPending) {
88 hr = interface->StepThread(thread);
89
90 if (True(hr & Core::HaltReason::StepThread)) {
91 thread->SetStepState(StepState::StepPerformed);
92 }
93 } else {
94 hr = interface->RunThread(thread);
95 }
96
97 ExitContext();
98 }
99
100 // Determine why we stopped.
101 const bool supervisor_call = True(hr & Core::HaltReason::SupervisorCall);
102 const bool prefetch_abort = True(hr & Core::HaltReason::PrefetchAbort);
103 const bool breakpoint = True(hr & Core::HaltReason::InstructionBreakpoint);
104 const bool data_abort = True(hr & Core::HaltReason::DataAbort);
105 const bool interrupt = True(hr & Core::HaltReason::BreakLoop);
106
107 // Since scheduling may occur here, we cannot use any cached
108 // state after returning from calls we make.
109
110 // Notify the debugger and go to sleep if a breakpoint was hit,
111 // or if the thread is unable to continue for any reason.
112 if (breakpoint || prefetch_abort) {
113 if (breakpoint) {
114 interface->RewindBreakpointInstruction();
115 }
116 if (system.DebuggerEnabled()) {
117 system.GetDebugger().NotifyThreadStopped(thread);
118 } else {
119 interface->LogBacktrace(process);
120 }
121 thread->RequestSuspend(SuspendType::Debug);
122 return;
123 }
124
125 // Notify the debugger and go to sleep on data abort.
126 if (data_abort) {
127 if (system.DebuggerEnabled()) {
128 system.GetDebugger().NotifyThreadWatchpoint(thread, *interface->HaltedWatchpoint());
129 }
130 thread->RequestSuspend(SuspendType::Debug);
131 return;
132 }
133
134 // Handle system calls.
135 if (supervisor_call) {
136 // Perform call.
137 Svc::Call(system, interface->GetSvcNumber());
138 return;
139 }
140
141 // Handle external interrupt sources.
142 if (interrupt || m_is_single_core) {
143 return;
144 }
145 }
146}
147
148void PhysicalCore::LoadContext(const KThread* thread) {
149 auto* const process = thread->GetOwnerProcess();
150 if (!process) {
151 // Kernel threads do not run on emulated CPU cores.
40 return; 152 return;
41 } 153 }
42#endif 154
43#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) 155 auto* interface = process->GetArmInterface(m_core_index);
44 auto& kernel = m_system.Kernel(); 156 if (interface) {
45 if (!is_64_bit) { 157 interface->SetContext(thread->GetContext());
46 // We already initialized a 64-bit core, replace with a 32-bit one. 158 interface->SetTpidrroEl0(GetInteger(thread->GetTlsAddress()));
47 m_arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( 159 interface->SetWatchpointArray(&process->GetWatchpoints());
48 m_system, kernel.IsMulticore(),
49 reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()),
50 m_core_index);
51 } 160 }
52#else
53#error Platform not supported yet.
54#endif
55} 161}
56 162
57void PhysicalCore::Run() { 163void PhysicalCore::LoadSvcArguments(const KProcess& process, std::span<const uint64_t, 8> args) {
58 m_arm_interface->Run(); 164 process.GetArmInterface(m_core_index)->SetSvcArguments(args);
59 m_arm_interface->ClearExclusiveState(); 165}
166
167void PhysicalCore::SaveContext(KThread* thread) const {
168 auto* const process = thread->GetOwnerProcess();
169 if (!process) {
170 // Kernel threads do not run on emulated CPU cores.
171 return;
172 }
173
174 auto* interface = process->GetArmInterface(m_core_index);
175 if (interface) {
176 interface->GetContext(thread->GetContext());
177 }
178}
179
180void PhysicalCore::SaveSvcArguments(KProcess& process, std::span<uint64_t, 8> args) const {
181 process.GetArmInterface(m_core_index)->GetSvcArguments(args);
182}
183
184void PhysicalCore::CloneFpuStatus(KThread* dst) const {
185 auto* process = dst->GetOwnerProcess();
186
187 Svc::ThreadContext ctx{};
188 process->GetArmInterface(m_core_index)->GetContext(ctx);
189
190 dst->GetContext().fpcr = ctx.fpcr;
191 dst->GetContext().fpsr = ctx.fpsr;
192}
193
194void PhysicalCore::LogBacktrace() {
195 auto* process = GetCurrentProcessPointer(m_kernel);
196 if (!process) {
197 return;
198 }
199
200 auto* interface = process->GetArmInterface(m_core_index);
201 if (interface) {
202 interface->LogBacktrace(process);
203 }
60} 204}
61 205
62void PhysicalCore::Idle() { 206void PhysicalCore::Idle() {
@@ -69,16 +213,31 @@ bool PhysicalCore::IsInterrupted() const {
69} 213}
70 214
71void PhysicalCore::Interrupt() { 215void PhysicalCore::Interrupt() {
72 std::unique_lock lk{m_guard}; 216 // Lock core context.
217 std::scoped_lock lk{m_guard};
218
219 // Load members.
220 auto* arm_interface = m_arm_interface;
221 auto* thread = m_current_thread;
222
223 // Add interrupt flag.
73 m_is_interrupted = true; 224 m_is_interrupted = true;
74 m_arm_interface->SignalInterrupt(); 225
75 m_on_interrupt.notify_all(); 226 // Interrupt ourselves.
227 m_on_interrupt.notify_one();
228
229 // If there is no thread running, we are done.
230 if (arm_interface == nullptr) {
231 return;
232 }
233
234 // Interrupt the CPU.
235 arm_interface->SignalInterrupt(thread);
76} 236}
77 237
78void PhysicalCore::ClearInterrupt() { 238void PhysicalCore::ClearInterrupt() {
79 std::unique_lock lk{m_guard}; 239 std::scoped_lock lk{m_guard};
80 m_is_interrupted = false; 240 m_is_interrupted = false;
81 m_arm_interface->ClearInterrupt();
82} 241}
83 242
84} // namespace Kernel 243} // namespace Kernel
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h
index 5cb398fdc..bae4fe5b8 100644
--- a/src/core/hle/kernel/physical_core.h
+++ b/src/core/hle/kernel/physical_core.h
@@ -11,7 +11,7 @@
11#include "core/arm/arm_interface.h" 11#include "core/arm/arm_interface.h"
12 12
13namespace Kernel { 13namespace Kernel {
14class KScheduler; 14class KernelCore;
15} // namespace Kernel 15} // namespace Kernel
16 16
17namespace Core { 17namespace Core {
@@ -23,62 +23,55 @@ namespace Kernel {
23 23
24class PhysicalCore { 24class PhysicalCore {
25public: 25public:
26 PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_); 26 PhysicalCore(KernelCore& kernel, std::size_t core_index);
27 ~PhysicalCore(); 27 ~PhysicalCore();
28 28
29 YUZU_NON_COPYABLE(PhysicalCore); 29 YUZU_NON_COPYABLE(PhysicalCore);
30 YUZU_NON_MOVEABLE(PhysicalCore); 30 YUZU_NON_MOVEABLE(PhysicalCore);
31 31
32 /// Initialize the core for the specified parameters. 32 // Execute guest code running on the given thread.
33 void Initialize(bool is_64_bit); 33 void RunThread(KThread* thread);
34 34
35 /// Execute current jit state 35 // Copy context from thread to current core.
36 void Run(); 36 void LoadContext(const KThread* thread);
37 void LoadSvcArguments(const KProcess& process, std::span<const uint64_t, 8> args);
37 38
39 // Copy context from current core to thread.
40 void SaveContext(KThread* thread) const;
41 void SaveSvcArguments(KProcess& process, std::span<uint64_t, 8> args) const;
42
43 // Copy floating point status registers to the target thread.
44 void CloneFpuStatus(KThread* dst) const;
45
46 // Log backtrace of current processor state.
47 void LogBacktrace();
48
49 // Wait for an interrupt.
38 void Idle(); 50 void Idle();
39 51
40 /// Interrupt this physical core. 52 // Interrupt this core.
41 void Interrupt(); 53 void Interrupt();
42 54
43 /// Clear this core's interrupt 55 // Clear this core's interrupt.
44 void ClearInterrupt(); 56 void ClearInterrupt();
45 57
46 /// Check if this core is interrupted 58 // Check if this core is interrupted.
47 bool IsInterrupted() const; 59 bool IsInterrupted() const;
48 60
49 bool IsInitialized() const {
50 return m_arm_interface != nullptr;
51 }
52
53 Core::ARM_Interface& ArmInterface() {
54 return *m_arm_interface;
55 }
56
57 const Core::ARM_Interface& ArmInterface() const {
58 return *m_arm_interface;
59 }
60
61 std::size_t CoreIndex() const { 61 std::size_t CoreIndex() const {
62 return m_core_index; 62 return m_core_index;
63 } 63 }
64 64
65 Kernel::KScheduler& Scheduler() {
66 return m_scheduler;
67 }
68
69 const Kernel::KScheduler& Scheduler() const {
70 return m_scheduler;
71 }
72
73private: 65private:
66 KernelCore& m_kernel;
74 const std::size_t m_core_index; 67 const std::size_t m_core_index;
75 Core::System& m_system;
76 Kernel::KScheduler& m_scheduler;
77 68
78 std::mutex m_guard; 69 std::mutex m_guard;
79 std::condition_variable m_on_interrupt; 70 std::condition_variable m_on_interrupt;
80 std::unique_ptr<Core::ARM_Interface> m_arm_interface; 71 Core::ArmInterface* m_arm_interface{};
72 KThread* m_current_thread{};
81 bool m_is_interrupted{}; 73 bool m_is_interrupted{};
74 bool m_is_single_core{};
82}; 75};
83 76
84} // namespace Kernel 77} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index b76683969..c55dc0c8a 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -12,20 +12,20 @@
12 12
13namespace Kernel::Svc { 13namespace Kernel::Svc {
14 14
15static uint32_t GetReg32(Core::System& system, int n) { 15static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
16 return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n)); 16 return static_cast<uint32_t>(args[n]);
17} 17}
18 18
19static void SetReg32(Core::System& system, int n, uint32_t result) { 19static void SetArg32(std::span<uint64_t, 8> args, int n, uint32_t result) {
20 system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result)); 20 args[n] = result;
21} 21}
22 22
23static uint64_t GetReg64(Core::System& system, int n) { 23static uint64_t GetArg64(std::span<uint64_t, 8> args, int n) {
24 return system.CurrentArmInterface().GetReg(n); 24 return args[n];
25} 25}
26 26
27static void SetReg64(Core::System& system, int n, uint64_t result) { 27static void SetArg64(std::span<uint64_t, 8> args, int n, uint64_t result) {
28 system.CurrentArmInterface().SetReg(n, result); 28 args[n] = result;
29} 29}
30 30
31// Like bit_cast, but handles the case when the source and dest 31// Like bit_cast, but handles the case when the source and dest
@@ -79,37 +79,37 @@ static_assert(sizeof(int64_t) == 8);
79static_assert(sizeof(uint32_t) == 4); 79static_assert(sizeof(uint32_t) == 4);
80static_assert(sizeof(uint64_t) == 8); 80static_assert(sizeof(uint64_t) == 8);
81 81
82static void SvcWrap_SetHeapSize64From32(Core::System& system) { 82static void SvcWrap_SetHeapSize64From32(Core::System& system, std::span<uint64_t, 8> args) {
83 Result ret{}; 83 Result ret{};
84 84
85 uint64_t out_address{}; 85 uint64_t out_address{};
86 uint32_t size{}; 86 uint32_t size{};
87 87
88 size = Convert<uint32_t>(GetReg32(system, 1)); 88 size = Convert<uint32_t>(GetArg32(args, 1));
89 89
90 ret = SetHeapSize64From32(system, std::addressof(out_address), size); 90 ret = SetHeapSize64From32(system, std::addressof(out_address), size);
91 91
92 SetReg32(system, 0, Convert<uint32_t>(ret)); 92 SetArg32(args, 0, Convert<uint32_t>(ret));
93 SetReg32(system, 1, Convert<uint32_t>(out_address)); 93 SetArg32(args, 1, Convert<uint32_t>(out_address));
94} 94}
95 95
96static void SvcWrap_SetMemoryPermission64From32(Core::System& system) { 96static void SvcWrap_SetMemoryPermission64From32(Core::System& system, std::span<uint64_t, 8> args) {
97 Result ret{}; 97 Result ret{};
98 98
99 uint32_t address{}; 99 uint32_t address{};
100 uint32_t size{}; 100 uint32_t size{};
101 MemoryPermission perm{}; 101 MemoryPermission perm{};
102 102
103 address = Convert<uint32_t>(GetReg32(system, 0)); 103 address = Convert<uint32_t>(GetArg32(args, 0));
104 size = Convert<uint32_t>(GetReg32(system, 1)); 104 size = Convert<uint32_t>(GetArg32(args, 1));
105 perm = Convert<MemoryPermission>(GetReg32(system, 2)); 105 perm = Convert<MemoryPermission>(GetArg32(args, 2));
106 106
107 ret = SetMemoryPermission64From32(system, address, size, perm); 107 ret = SetMemoryPermission64From32(system, address, size, perm);
108 108
109 SetReg32(system, 0, Convert<uint32_t>(ret)); 109 SetArg32(args, 0, Convert<uint32_t>(ret));
110} 110}
111 111
112static void SvcWrap_SetMemoryAttribute64From32(Core::System& system) { 112static void SvcWrap_SetMemoryAttribute64From32(Core::System& system, std::span<uint64_t, 8> args) {
113 Result ret{}; 113 Result ret{};
114 114
115 uint32_t address{}; 115 uint32_t address{};
@@ -117,69 +117,69 @@ static void SvcWrap_SetMemoryAttribute64From32(Core::System& system) {
117 uint32_t mask{}; 117 uint32_t mask{};
118 uint32_t attr{}; 118 uint32_t attr{};
119 119
120 address = Convert<uint32_t>(GetReg32(system, 0)); 120 address = Convert<uint32_t>(GetArg32(args, 0));
121 size = Convert<uint32_t>(GetReg32(system, 1)); 121 size = Convert<uint32_t>(GetArg32(args, 1));
122 mask = Convert<uint32_t>(GetReg32(system, 2)); 122 mask = Convert<uint32_t>(GetArg32(args, 2));
123 attr = Convert<uint32_t>(GetReg32(system, 3)); 123 attr = Convert<uint32_t>(GetArg32(args, 3));
124 124
125 ret = SetMemoryAttribute64From32(system, address, size, mask, attr); 125 ret = SetMemoryAttribute64From32(system, address, size, mask, attr);
126 126
127 SetReg32(system, 0, Convert<uint32_t>(ret)); 127 SetArg32(args, 0, Convert<uint32_t>(ret));
128} 128}
129 129
130static void SvcWrap_MapMemory64From32(Core::System& system) { 130static void SvcWrap_MapMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
131 Result ret{}; 131 Result ret{};
132 132
133 uint32_t dst_address{}; 133 uint32_t dst_address{};
134 uint32_t src_address{}; 134 uint32_t src_address{};
135 uint32_t size{}; 135 uint32_t size{};
136 136
137 dst_address = Convert<uint32_t>(GetReg32(system, 0)); 137 dst_address = Convert<uint32_t>(GetArg32(args, 0));
138 src_address = Convert<uint32_t>(GetReg32(system, 1)); 138 src_address = Convert<uint32_t>(GetArg32(args, 1));
139 size = Convert<uint32_t>(GetReg32(system, 2)); 139 size = Convert<uint32_t>(GetArg32(args, 2));
140 140
141 ret = MapMemory64From32(system, dst_address, src_address, size); 141 ret = MapMemory64From32(system, dst_address, src_address, size);
142 142
143 SetReg32(system, 0, Convert<uint32_t>(ret)); 143 SetArg32(args, 0, Convert<uint32_t>(ret));
144} 144}
145 145
146static void SvcWrap_UnmapMemory64From32(Core::System& system) { 146static void SvcWrap_UnmapMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
147 Result ret{}; 147 Result ret{};
148 148
149 uint32_t dst_address{}; 149 uint32_t dst_address{};
150 uint32_t src_address{}; 150 uint32_t src_address{};
151 uint32_t size{}; 151 uint32_t size{};
152 152
153 dst_address = Convert<uint32_t>(GetReg32(system, 0)); 153 dst_address = Convert<uint32_t>(GetArg32(args, 0));
154 src_address = Convert<uint32_t>(GetReg32(system, 1)); 154 src_address = Convert<uint32_t>(GetArg32(args, 1));
155 size = Convert<uint32_t>(GetReg32(system, 2)); 155 size = Convert<uint32_t>(GetArg32(args, 2));
156 156
157 ret = UnmapMemory64From32(system, dst_address, src_address, size); 157 ret = UnmapMemory64From32(system, dst_address, src_address, size);
158 158
159 SetReg32(system, 0, Convert<uint32_t>(ret)); 159 SetArg32(args, 0, Convert<uint32_t>(ret));
160} 160}
161 161
162static void SvcWrap_QueryMemory64From32(Core::System& system) { 162static void SvcWrap_QueryMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
163 Result ret{}; 163 Result ret{};
164 164
165 PageInfo out_page_info{}; 165 PageInfo out_page_info{};
166 uint32_t out_memory_info{}; 166 uint32_t out_memory_info{};
167 uint32_t address{}; 167 uint32_t address{};
168 168
169 out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); 169 out_memory_info = Convert<uint32_t>(GetArg32(args, 0));
170 address = Convert<uint32_t>(GetReg32(system, 2)); 170 address = Convert<uint32_t>(GetArg32(args, 2));
171 171
172 ret = QueryMemory64From32(system, out_memory_info, std::addressof(out_page_info), address); 172 ret = QueryMemory64From32(system, out_memory_info, std::addressof(out_page_info), address);
173 173
174 SetReg32(system, 0, Convert<uint32_t>(ret)); 174 SetArg32(args, 0, Convert<uint32_t>(ret));
175 SetReg32(system, 1, Convert<uint32_t>(out_page_info)); 175 SetArg32(args, 1, Convert<uint32_t>(out_page_info));
176} 176}
177 177
178static void SvcWrap_ExitProcess64From32(Core::System& system) { 178static void SvcWrap_ExitProcess64From32(Core::System& system, std::span<uint64_t, 8> args) {
179 ExitProcess64From32(system); 179 ExitProcess64From32(system);
180} 180}
181 181
182static void SvcWrap_CreateThread64From32(Core::System& system) { 182static void SvcWrap_CreateThread64From32(Core::System& system, std::span<uint64_t, 8> args) {
183 Result ret{}; 183 Result ret{};
184 184
185 Handle out_handle{}; 185 Handle out_handle{};
@@ -189,143 +189,143 @@ static void SvcWrap_CreateThread64From32(Core::System& system) {
189 int32_t priority{}; 189 int32_t priority{};
190 int32_t core_id{}; 190 int32_t core_id{};
191 191
192 func = Convert<uint32_t>(GetReg32(system, 1)); 192 func = Convert<uint32_t>(GetArg32(args, 1));
193 arg = Convert<uint32_t>(GetReg32(system, 2)); 193 arg = Convert<uint32_t>(GetArg32(args, 2));
194 stack_bottom = Convert<uint32_t>(GetReg32(system, 3)); 194 stack_bottom = Convert<uint32_t>(GetArg32(args, 3));
195 priority = Convert<int32_t>(GetReg32(system, 0)); 195 priority = Convert<int32_t>(GetArg32(args, 0));
196 core_id = Convert<int32_t>(GetReg32(system, 4)); 196 core_id = Convert<int32_t>(GetArg32(args, 4));
197 197
198 ret = CreateThread64From32(system, std::addressof(out_handle), func, arg, stack_bottom, priority, core_id); 198 ret = CreateThread64From32(system, std::addressof(out_handle), func, arg, stack_bottom, priority, core_id);
199 199
200 SetReg32(system, 0, Convert<uint32_t>(ret)); 200 SetArg32(args, 0, Convert<uint32_t>(ret));
201 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 201 SetArg32(args, 1, Convert<uint32_t>(out_handle));
202} 202}
203 203
204static void SvcWrap_StartThread64From32(Core::System& system) { 204static void SvcWrap_StartThread64From32(Core::System& system, std::span<uint64_t, 8> args) {
205 Result ret{}; 205 Result ret{};
206 206
207 Handle thread_handle{}; 207 Handle thread_handle{};
208 208
209 thread_handle = Convert<Handle>(GetReg32(system, 0)); 209 thread_handle = Convert<Handle>(GetArg32(args, 0));
210 210
211 ret = StartThread64From32(system, thread_handle); 211 ret = StartThread64From32(system, thread_handle);
212 212
213 SetReg32(system, 0, Convert<uint32_t>(ret)); 213 SetArg32(args, 0, Convert<uint32_t>(ret));
214} 214}
215 215
216static void SvcWrap_ExitThread64From32(Core::System& system) { 216static void SvcWrap_ExitThread64From32(Core::System& system, std::span<uint64_t, 8> args) {
217 ExitThread64From32(system); 217 ExitThread64From32(system);
218} 218}
219 219
220static void SvcWrap_SleepThread64From32(Core::System& system) { 220static void SvcWrap_SleepThread64From32(Core::System& system, std::span<uint64_t, 8> args) {
221 int64_t ns{}; 221 int64_t ns{};
222 222
223 std::array<uint32_t, 2> ns_gather{}; 223 std::array<uint32_t, 2> ns_gather{};
224 ns_gather[0] = GetReg32(system, 0); 224 ns_gather[0] = GetArg32(args, 0);
225 ns_gather[1] = GetReg32(system, 1); 225 ns_gather[1] = GetArg32(args, 1);
226 ns = Convert<int64_t>(ns_gather); 226 ns = Convert<int64_t>(ns_gather);
227 227
228 SleepThread64From32(system, ns); 228 SleepThread64From32(system, ns);
229} 229}
230 230
231static void SvcWrap_GetThreadPriority64From32(Core::System& system) { 231static void SvcWrap_GetThreadPriority64From32(Core::System& system, std::span<uint64_t, 8> args) {
232 Result ret{}; 232 Result ret{};
233 233
234 int32_t out_priority{}; 234 int32_t out_priority{};
235 Handle thread_handle{}; 235 Handle thread_handle{};
236 236
237 thread_handle = Convert<Handle>(GetReg32(system, 1)); 237 thread_handle = Convert<Handle>(GetArg32(args, 1));
238 238
239 ret = GetThreadPriority64From32(system, std::addressof(out_priority), thread_handle); 239 ret = GetThreadPriority64From32(system, std::addressof(out_priority), thread_handle);
240 240
241 SetReg32(system, 0, Convert<uint32_t>(ret)); 241 SetArg32(args, 0, Convert<uint32_t>(ret));
242 SetReg32(system, 1, Convert<uint32_t>(out_priority)); 242 SetArg32(args, 1, Convert<uint32_t>(out_priority));
243} 243}
244 244
245static void SvcWrap_SetThreadPriority64From32(Core::System& system) { 245static void SvcWrap_SetThreadPriority64From32(Core::System& system, std::span<uint64_t, 8> args) {
246 Result ret{}; 246 Result ret{};
247 247
248 Handle thread_handle{}; 248 Handle thread_handle{};
249 int32_t priority{}; 249 int32_t priority{};
250 250
251 thread_handle = Convert<Handle>(GetReg32(system, 0)); 251 thread_handle = Convert<Handle>(GetArg32(args, 0));
252 priority = Convert<int32_t>(GetReg32(system, 1)); 252 priority = Convert<int32_t>(GetArg32(args, 1));
253 253
254 ret = SetThreadPriority64From32(system, thread_handle, priority); 254 ret = SetThreadPriority64From32(system, thread_handle, priority);
255 255
256 SetReg32(system, 0, Convert<uint32_t>(ret)); 256 SetArg32(args, 0, Convert<uint32_t>(ret));
257} 257}
258 258
259static void SvcWrap_GetThreadCoreMask64From32(Core::System& system) { 259static void SvcWrap_GetThreadCoreMask64From32(Core::System& system, std::span<uint64_t, 8> args) {
260 Result ret{}; 260 Result ret{};
261 261
262 int32_t out_core_id{}; 262 int32_t out_core_id{};
263 uint64_t out_affinity_mask{}; 263 uint64_t out_affinity_mask{};
264 Handle thread_handle{}; 264 Handle thread_handle{};
265 265
266 thread_handle = Convert<Handle>(GetReg32(system, 2)); 266 thread_handle = Convert<Handle>(GetArg32(args, 2));
267 267
268 ret = GetThreadCoreMask64From32(system, std::addressof(out_core_id), std::addressof(out_affinity_mask), thread_handle); 268 ret = GetThreadCoreMask64From32(system, std::addressof(out_core_id), std::addressof(out_affinity_mask), thread_handle);
269 269
270 SetReg32(system, 0, Convert<uint32_t>(ret)); 270 SetArg32(args, 0, Convert<uint32_t>(ret));
271 SetReg32(system, 1, Convert<uint32_t>(out_core_id)); 271 SetArg32(args, 1, Convert<uint32_t>(out_core_id));
272 auto out_affinity_mask_scatter = Convert<std::array<uint32_t, 2>>(out_affinity_mask); 272 auto out_affinity_mask_scatter = Convert<std::array<uint32_t, 2>>(out_affinity_mask);
273 SetReg32(system, 2, out_affinity_mask_scatter[0]); 273 SetArg32(args, 2, out_affinity_mask_scatter[0]);
274 SetReg32(system, 3, out_affinity_mask_scatter[1]); 274 SetArg32(args, 3, out_affinity_mask_scatter[1]);
275} 275}
276 276
277static void SvcWrap_SetThreadCoreMask64From32(Core::System& system) { 277static void SvcWrap_SetThreadCoreMask64From32(Core::System& system, std::span<uint64_t, 8> args) {
278 Result ret{}; 278 Result ret{};
279 279
280 Handle thread_handle{}; 280 Handle thread_handle{};
281 int32_t core_id{}; 281 int32_t core_id{};
282 uint64_t affinity_mask{}; 282 uint64_t affinity_mask{};
283 283
284 thread_handle = Convert<Handle>(GetReg32(system, 0)); 284 thread_handle = Convert<Handle>(GetArg32(args, 0));
285 core_id = Convert<int32_t>(GetReg32(system, 1)); 285 core_id = Convert<int32_t>(GetArg32(args, 1));
286 std::array<uint32_t, 2> affinity_mask_gather{}; 286 std::array<uint32_t, 2> affinity_mask_gather{};
287 affinity_mask_gather[0] = GetReg32(system, 2); 287 affinity_mask_gather[0] = GetArg32(args, 2);
288 affinity_mask_gather[1] = GetReg32(system, 3); 288 affinity_mask_gather[1] = GetArg32(args, 3);
289 affinity_mask = Convert<uint64_t>(affinity_mask_gather); 289 affinity_mask = Convert<uint64_t>(affinity_mask_gather);
290 290
291 ret = SetThreadCoreMask64From32(system, thread_handle, core_id, affinity_mask); 291 ret = SetThreadCoreMask64From32(system, thread_handle, core_id, affinity_mask);
292 292
293 SetReg32(system, 0, Convert<uint32_t>(ret)); 293 SetArg32(args, 0, Convert<uint32_t>(ret));
294} 294}
295 295
296static void SvcWrap_GetCurrentProcessorNumber64From32(Core::System& system) { 296static void SvcWrap_GetCurrentProcessorNumber64From32(Core::System& system, std::span<uint64_t, 8> args) {
297 int32_t ret{}; 297 int32_t ret{};
298 298
299 ret = GetCurrentProcessorNumber64From32(system); 299 ret = GetCurrentProcessorNumber64From32(system);
300 300
301 SetReg32(system, 0, Convert<uint32_t>(ret)); 301 SetArg32(args, 0, Convert<uint32_t>(ret));
302} 302}
303 303
304static void SvcWrap_SignalEvent64From32(Core::System& system) { 304static void SvcWrap_SignalEvent64From32(Core::System& system, std::span<uint64_t, 8> args) {
305 Result ret{}; 305 Result ret{};
306 306
307 Handle event_handle{}; 307 Handle event_handle{};
308 308
309 event_handle = Convert<Handle>(GetReg32(system, 0)); 309 event_handle = Convert<Handle>(GetArg32(args, 0));
310 310
311 ret = SignalEvent64From32(system, event_handle); 311 ret = SignalEvent64From32(system, event_handle);
312 312
313 SetReg32(system, 0, Convert<uint32_t>(ret)); 313 SetArg32(args, 0, Convert<uint32_t>(ret));
314} 314}
315 315
316static void SvcWrap_ClearEvent64From32(Core::System& system) { 316static void SvcWrap_ClearEvent64From32(Core::System& system, std::span<uint64_t, 8> args) {
317 Result ret{}; 317 Result ret{};
318 318
319 Handle event_handle{}; 319 Handle event_handle{};
320 320
321 event_handle = Convert<Handle>(GetReg32(system, 0)); 321 event_handle = Convert<Handle>(GetArg32(args, 0));
322 322
323 ret = ClearEvent64From32(system, event_handle); 323 ret = ClearEvent64From32(system, event_handle);
324 324
325 SetReg32(system, 0, Convert<uint32_t>(ret)); 325 SetArg32(args, 0, Convert<uint32_t>(ret));
326} 326}
327 327
328static void SvcWrap_MapSharedMemory64From32(Core::System& system) { 328static void SvcWrap_MapSharedMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
329 Result ret{}; 329 Result ret{};
330 330
331 Handle shmem_handle{}; 331 Handle shmem_handle{};
@@ -333,33 +333,33 @@ static void SvcWrap_MapSharedMemory64From32(Core::System& system) {
333 uint32_t size{}; 333 uint32_t size{};
334 MemoryPermission map_perm{}; 334 MemoryPermission map_perm{};
335 335
336 shmem_handle = Convert<Handle>(GetReg32(system, 0)); 336 shmem_handle = Convert<Handle>(GetArg32(args, 0));
337 address = Convert<uint32_t>(GetReg32(system, 1)); 337 address = Convert<uint32_t>(GetArg32(args, 1));
338 size = Convert<uint32_t>(GetReg32(system, 2)); 338 size = Convert<uint32_t>(GetArg32(args, 2));
339 map_perm = Convert<MemoryPermission>(GetReg32(system, 3)); 339 map_perm = Convert<MemoryPermission>(GetArg32(args, 3));
340 340
341 ret = MapSharedMemory64From32(system, shmem_handle, address, size, map_perm); 341 ret = MapSharedMemory64From32(system, shmem_handle, address, size, map_perm);
342 342
343 SetReg32(system, 0, Convert<uint32_t>(ret)); 343 SetArg32(args, 0, Convert<uint32_t>(ret));
344} 344}
345 345
346static void SvcWrap_UnmapSharedMemory64From32(Core::System& system) { 346static void SvcWrap_UnmapSharedMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
347 Result ret{}; 347 Result ret{};
348 348
349 Handle shmem_handle{}; 349 Handle shmem_handle{};
350 uint32_t address{}; 350 uint32_t address{};
351 uint32_t size{}; 351 uint32_t size{};
352 352
353 shmem_handle = Convert<Handle>(GetReg32(system, 0)); 353 shmem_handle = Convert<Handle>(GetArg32(args, 0));
354 address = Convert<uint32_t>(GetReg32(system, 1)); 354 address = Convert<uint32_t>(GetArg32(args, 1));
355 size = Convert<uint32_t>(GetReg32(system, 2)); 355 size = Convert<uint32_t>(GetArg32(args, 2));
356 356
357 ret = UnmapSharedMemory64From32(system, shmem_handle, address, size); 357 ret = UnmapSharedMemory64From32(system, shmem_handle, address, size);
358 358
359 SetReg32(system, 0, Convert<uint32_t>(ret)); 359 SetArg32(args, 0, Convert<uint32_t>(ret));
360} 360}
361 361
362static void SvcWrap_CreateTransferMemory64From32(Core::System& system) { 362static void SvcWrap_CreateTransferMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
363 Result ret{}; 363 Result ret{};
364 364
365 Handle out_handle{}; 365 Handle out_handle{};
@@ -367,41 +367,41 @@ static void SvcWrap_CreateTransferMemory64From32(Core::System& system) {
367 uint32_t size{}; 367 uint32_t size{};
368 MemoryPermission map_perm{}; 368 MemoryPermission map_perm{};
369 369
370 address = Convert<uint32_t>(GetReg32(system, 1)); 370 address = Convert<uint32_t>(GetArg32(args, 1));
371 size = Convert<uint32_t>(GetReg32(system, 2)); 371 size = Convert<uint32_t>(GetArg32(args, 2));
372 map_perm = Convert<MemoryPermission>(GetReg32(system, 3)); 372 map_perm = Convert<MemoryPermission>(GetArg32(args, 3));
373 373
374 ret = CreateTransferMemory64From32(system, std::addressof(out_handle), address, size, map_perm); 374 ret = CreateTransferMemory64From32(system, std::addressof(out_handle), address, size, map_perm);
375 375
376 SetReg32(system, 0, Convert<uint32_t>(ret)); 376 SetArg32(args, 0, Convert<uint32_t>(ret));
377 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 377 SetArg32(args, 1, Convert<uint32_t>(out_handle));
378} 378}
379 379
380static void SvcWrap_CloseHandle64From32(Core::System& system) { 380static void SvcWrap_CloseHandle64From32(Core::System& system, std::span<uint64_t, 8> args) {
381 Result ret{}; 381 Result ret{};
382 382
383 Handle handle{}; 383 Handle handle{};
384 384
385 handle = Convert<Handle>(GetReg32(system, 0)); 385 handle = Convert<Handle>(GetArg32(args, 0));
386 386
387 ret = CloseHandle64From32(system, handle); 387 ret = CloseHandle64From32(system, handle);
388 388
389 SetReg32(system, 0, Convert<uint32_t>(ret)); 389 SetArg32(args, 0, Convert<uint32_t>(ret));
390} 390}
391 391
392static void SvcWrap_ResetSignal64From32(Core::System& system) { 392static void SvcWrap_ResetSignal64From32(Core::System& system, std::span<uint64_t, 8> args) {
393 Result ret{}; 393 Result ret{};
394 394
395 Handle handle{}; 395 Handle handle{};
396 396
397 handle = Convert<Handle>(GetReg32(system, 0)); 397 handle = Convert<Handle>(GetArg32(args, 0));
398 398
399 ret = ResetSignal64From32(system, handle); 399 ret = ResetSignal64From32(system, handle);
400 400
401 SetReg32(system, 0, Convert<uint32_t>(ret)); 401 SetArg32(args, 0, Convert<uint32_t>(ret));
402} 402}
403 403
404static void SvcWrap_WaitSynchronization64From32(Core::System& system) { 404static void SvcWrap_WaitSynchronization64From32(Core::System& system, std::span<uint64_t, 8> args) {
405 Result ret{}; 405 Result ret{};
406 406
407 int32_t out_index{}; 407 int32_t out_index{};
@@ -409,60 +409,60 @@ static void SvcWrap_WaitSynchronization64From32(Core::System& system) {
409 int32_t num_handles{}; 409 int32_t num_handles{};
410 int64_t timeout_ns{}; 410 int64_t timeout_ns{};
411 411
412 handles = Convert<uint32_t>(GetReg32(system, 1)); 412 handles = Convert<uint32_t>(GetArg32(args, 1));
413 num_handles = Convert<int32_t>(GetReg32(system, 2)); 413 num_handles = Convert<int32_t>(GetArg32(args, 2));
414 std::array<uint32_t, 2> timeout_ns_gather{}; 414 std::array<uint32_t, 2> timeout_ns_gather{};
415 timeout_ns_gather[0] = GetReg32(system, 0); 415 timeout_ns_gather[0] = GetArg32(args, 0);
416 timeout_ns_gather[1] = GetReg32(system, 3); 416 timeout_ns_gather[1] = GetArg32(args, 3);
417 timeout_ns = Convert<int64_t>(timeout_ns_gather); 417 timeout_ns = Convert<int64_t>(timeout_ns_gather);
418 418
419 ret = WaitSynchronization64From32(system, std::addressof(out_index), handles, num_handles, timeout_ns); 419 ret = WaitSynchronization64From32(system, std::addressof(out_index), handles, num_handles, timeout_ns);
420 420
421 SetReg32(system, 0, Convert<uint32_t>(ret)); 421 SetArg32(args, 0, Convert<uint32_t>(ret));
422 SetReg32(system, 1, Convert<uint32_t>(out_index)); 422 SetArg32(args, 1, Convert<uint32_t>(out_index));
423} 423}
424 424
425static void SvcWrap_CancelSynchronization64From32(Core::System& system) { 425static void SvcWrap_CancelSynchronization64From32(Core::System& system, std::span<uint64_t, 8> args) {
426 Result ret{}; 426 Result ret{};
427 427
428 Handle handle{}; 428 Handle handle{};
429 429
430 handle = Convert<Handle>(GetReg32(system, 0)); 430 handle = Convert<Handle>(GetArg32(args, 0));
431 431
432 ret = CancelSynchronization64From32(system, handle); 432 ret = CancelSynchronization64From32(system, handle);
433 433
434 SetReg32(system, 0, Convert<uint32_t>(ret)); 434 SetArg32(args, 0, Convert<uint32_t>(ret));
435} 435}
436 436
437static void SvcWrap_ArbitrateLock64From32(Core::System& system) { 437static void SvcWrap_ArbitrateLock64From32(Core::System& system, std::span<uint64_t, 8> args) {
438 Result ret{}; 438 Result ret{};
439 439
440 Handle thread_handle{}; 440 Handle thread_handle{};
441 uint32_t address{}; 441 uint32_t address{};
442 uint32_t tag{}; 442 uint32_t tag{};
443 443
444 thread_handle = Convert<Handle>(GetReg32(system, 0)); 444 thread_handle = Convert<Handle>(GetArg32(args, 0));
445 address = Convert<uint32_t>(GetReg32(system, 1)); 445 address = Convert<uint32_t>(GetArg32(args, 1));
446 tag = Convert<uint32_t>(GetReg32(system, 2)); 446 tag = Convert<uint32_t>(GetArg32(args, 2));
447 447
448 ret = ArbitrateLock64From32(system, thread_handle, address, tag); 448 ret = ArbitrateLock64From32(system, thread_handle, address, tag);
449 449
450 SetReg32(system, 0, Convert<uint32_t>(ret)); 450 SetArg32(args, 0, Convert<uint32_t>(ret));
451} 451}
452 452
453static void SvcWrap_ArbitrateUnlock64From32(Core::System& system) { 453static void SvcWrap_ArbitrateUnlock64From32(Core::System& system, std::span<uint64_t, 8> args) {
454 Result ret{}; 454 Result ret{};
455 455
456 uint32_t address{}; 456 uint32_t address{};
457 457
458 address = Convert<uint32_t>(GetReg32(system, 0)); 458 address = Convert<uint32_t>(GetArg32(args, 0));
459 459
460 ret = ArbitrateUnlock64From32(system, address); 460 ret = ArbitrateUnlock64From32(system, address);
461 461
462 SetReg32(system, 0, Convert<uint32_t>(ret)); 462 SetArg32(args, 0, Convert<uint32_t>(ret));
463} 463}
464 464
465static void SvcWrap_WaitProcessWideKeyAtomic64From32(Core::System& system) { 465static void SvcWrap_WaitProcessWideKeyAtomic64From32(Core::System& system, std::span<uint64_t, 8> args) {
466 Result ret{}; 466 Result ret{};
467 467
468 uint32_t address{}; 468 uint32_t address{};
@@ -470,82 +470,82 @@ static void SvcWrap_WaitProcessWideKeyAtomic64From32(Core::System& system) {
470 uint32_t tag{}; 470 uint32_t tag{};
471 int64_t timeout_ns{}; 471 int64_t timeout_ns{};
472 472
473 address = Convert<uint32_t>(GetReg32(system, 0)); 473 address = Convert<uint32_t>(GetArg32(args, 0));
474 cv_key = Convert<uint32_t>(GetReg32(system, 1)); 474 cv_key = Convert<uint32_t>(GetArg32(args, 1));
475 tag = Convert<uint32_t>(GetReg32(system, 2)); 475 tag = Convert<uint32_t>(GetArg32(args, 2));
476 std::array<uint32_t, 2> timeout_ns_gather{}; 476 std::array<uint32_t, 2> timeout_ns_gather{};
477 timeout_ns_gather[0] = GetReg32(system, 3); 477 timeout_ns_gather[0] = GetArg32(args, 3);
478 timeout_ns_gather[1] = GetReg32(system, 4); 478 timeout_ns_gather[1] = GetArg32(args, 4);
479 timeout_ns = Convert<int64_t>(timeout_ns_gather); 479 timeout_ns = Convert<int64_t>(timeout_ns_gather);
480 480
481 ret = WaitProcessWideKeyAtomic64From32(system, address, cv_key, tag, timeout_ns); 481 ret = WaitProcessWideKeyAtomic64From32(system, address, cv_key, tag, timeout_ns);
482 482
483 SetReg32(system, 0, Convert<uint32_t>(ret)); 483 SetArg32(args, 0, Convert<uint32_t>(ret));
484} 484}
485 485
486static void SvcWrap_SignalProcessWideKey64From32(Core::System& system) { 486static void SvcWrap_SignalProcessWideKey64From32(Core::System& system, std::span<uint64_t, 8> args) {
487 uint32_t cv_key{}; 487 uint32_t cv_key{};
488 int32_t count{}; 488 int32_t count{};
489 489
490 cv_key = Convert<uint32_t>(GetReg32(system, 0)); 490 cv_key = Convert<uint32_t>(GetArg32(args, 0));
491 count = Convert<int32_t>(GetReg32(system, 1)); 491 count = Convert<int32_t>(GetArg32(args, 1));
492 492
493 SignalProcessWideKey64From32(system, cv_key, count); 493 SignalProcessWideKey64From32(system, cv_key, count);
494} 494}
495 495
496static void SvcWrap_GetSystemTick64From32(Core::System& system) { 496static void SvcWrap_GetSystemTick64From32(Core::System& system, std::span<uint64_t, 8> args) {
497 int64_t ret{}; 497 int64_t ret{};
498 498
499 ret = GetSystemTick64From32(system); 499 ret = GetSystemTick64From32(system);
500 500
501 auto ret_scatter = Convert<std::array<uint32_t, 2>>(ret); 501 auto ret_scatter = Convert<std::array<uint32_t, 2>>(ret);
502 SetReg32(system, 0, ret_scatter[0]); 502 SetArg32(args, 0, ret_scatter[0]);
503 SetReg32(system, 1, ret_scatter[1]); 503 SetArg32(args, 1, ret_scatter[1]);
504} 504}
505 505
506static void SvcWrap_ConnectToNamedPort64From32(Core::System& system) { 506static void SvcWrap_ConnectToNamedPort64From32(Core::System& system, std::span<uint64_t, 8> args) {
507 Result ret{}; 507 Result ret{};
508 508
509 Handle out_handle{}; 509 Handle out_handle{};
510 uint32_t name{}; 510 uint32_t name{};
511 511
512 name = Convert<uint32_t>(GetReg32(system, 1)); 512 name = Convert<uint32_t>(GetArg32(args, 1));
513 513
514 ret = ConnectToNamedPort64From32(system, std::addressof(out_handle), name); 514 ret = ConnectToNamedPort64From32(system, std::addressof(out_handle), name);
515 515
516 SetReg32(system, 0, Convert<uint32_t>(ret)); 516 SetArg32(args, 0, Convert<uint32_t>(ret));
517 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 517 SetArg32(args, 1, Convert<uint32_t>(out_handle));
518} 518}
519 519
520static void SvcWrap_SendSyncRequest64From32(Core::System& system) { 520static void SvcWrap_SendSyncRequest64From32(Core::System& system, std::span<uint64_t, 8> args) {
521 Result ret{}; 521 Result ret{};
522 522
523 Handle session_handle{}; 523 Handle session_handle{};
524 524
525 session_handle = Convert<Handle>(GetReg32(system, 0)); 525 session_handle = Convert<Handle>(GetArg32(args, 0));
526 526
527 ret = SendSyncRequest64From32(system, session_handle); 527 ret = SendSyncRequest64From32(system, session_handle);
528 528
529 SetReg32(system, 0, Convert<uint32_t>(ret)); 529 SetArg32(args, 0, Convert<uint32_t>(ret));
530} 530}
531 531
532static void SvcWrap_SendSyncRequestWithUserBuffer64From32(Core::System& system) { 532static void SvcWrap_SendSyncRequestWithUserBuffer64From32(Core::System& system, std::span<uint64_t, 8> args) {
533 Result ret{}; 533 Result ret{};
534 534
535 uint32_t message_buffer{}; 535 uint32_t message_buffer{};
536 uint32_t message_buffer_size{}; 536 uint32_t message_buffer_size{};
537 Handle session_handle{}; 537 Handle session_handle{};
538 538
539 message_buffer = Convert<uint32_t>(GetReg32(system, 0)); 539 message_buffer = Convert<uint32_t>(GetArg32(args, 0));
540 message_buffer_size = Convert<uint32_t>(GetReg32(system, 1)); 540 message_buffer_size = Convert<uint32_t>(GetArg32(args, 1));
541 session_handle = Convert<Handle>(GetReg32(system, 2)); 541 session_handle = Convert<Handle>(GetArg32(args, 2));
542 542
543 ret = SendSyncRequestWithUserBuffer64From32(system, message_buffer, message_buffer_size, session_handle); 543 ret = SendSyncRequestWithUserBuffer64From32(system, message_buffer, message_buffer_size, session_handle);
544 544
545 SetReg32(system, 0, Convert<uint32_t>(ret)); 545 SetArg32(args, 0, Convert<uint32_t>(ret));
546} 546}
547 547
548static void SvcWrap_SendAsyncRequestWithUserBuffer64From32(Core::System& system) { 548static void SvcWrap_SendAsyncRequestWithUserBuffer64From32(Core::System& system, std::span<uint64_t, 8> args) {
549 Result ret{}; 549 Result ret{};
550 550
551 Handle out_event_handle{}; 551 Handle out_event_handle{};
@@ -553,83 +553,83 @@ static void SvcWrap_SendAsyncRequestWithUserBuffer64From32(Core::System& system)
553 uint32_t message_buffer_size{}; 553 uint32_t message_buffer_size{};
554 Handle session_handle{}; 554 Handle session_handle{};
555 555
556 message_buffer = Convert<uint32_t>(GetReg32(system, 1)); 556 message_buffer = Convert<uint32_t>(GetArg32(args, 1));
557 message_buffer_size = Convert<uint32_t>(GetReg32(system, 2)); 557 message_buffer_size = Convert<uint32_t>(GetArg32(args, 2));
558 session_handle = Convert<Handle>(GetReg32(system, 3)); 558 session_handle = Convert<Handle>(GetArg32(args, 3));
559 559
560 ret = SendAsyncRequestWithUserBuffer64From32(system, std::addressof(out_event_handle), message_buffer, message_buffer_size, session_handle); 560 ret = SendAsyncRequestWithUserBuffer64From32(system, std::addressof(out_event_handle), message_buffer, message_buffer_size, session_handle);
561 561
562 SetReg32(system, 0, Convert<uint32_t>(ret)); 562 SetArg32(args, 0, Convert<uint32_t>(ret));
563 SetReg32(system, 1, Convert<uint32_t>(out_event_handle)); 563 SetArg32(args, 1, Convert<uint32_t>(out_event_handle));
564} 564}
565 565
566static void SvcWrap_GetProcessId64From32(Core::System& system) { 566static void SvcWrap_GetProcessId64From32(Core::System& system, std::span<uint64_t, 8> args) {
567 Result ret{}; 567 Result ret{};
568 568
569 uint64_t out_process_id{}; 569 uint64_t out_process_id{};
570 Handle process_handle{}; 570 Handle process_handle{};
571 571
572 process_handle = Convert<Handle>(GetReg32(system, 1)); 572 process_handle = Convert<Handle>(GetArg32(args, 1));
573 573
574 ret = GetProcessId64From32(system, std::addressof(out_process_id), process_handle); 574 ret = GetProcessId64From32(system, std::addressof(out_process_id), process_handle);
575 575
576 SetReg32(system, 0, Convert<uint32_t>(ret)); 576 SetArg32(args, 0, Convert<uint32_t>(ret));
577 auto out_process_id_scatter = Convert<std::array<uint32_t, 2>>(out_process_id); 577 auto out_process_id_scatter = Convert<std::array<uint32_t, 2>>(out_process_id);
578 SetReg32(system, 1, out_process_id_scatter[0]); 578 SetArg32(args, 1, out_process_id_scatter[0]);
579 SetReg32(system, 2, out_process_id_scatter[1]); 579 SetArg32(args, 2, out_process_id_scatter[1]);
580} 580}
581 581
582static void SvcWrap_GetThreadId64From32(Core::System& system) { 582static void SvcWrap_GetThreadId64From32(Core::System& system, std::span<uint64_t, 8> args) {
583 Result ret{}; 583 Result ret{};
584 584
585 uint64_t out_thread_id{}; 585 uint64_t out_thread_id{};
586 Handle thread_handle{}; 586 Handle thread_handle{};
587 587
588 thread_handle = Convert<Handle>(GetReg32(system, 1)); 588 thread_handle = Convert<Handle>(GetArg32(args, 1));
589 589
590 ret = GetThreadId64From32(system, std::addressof(out_thread_id), thread_handle); 590 ret = GetThreadId64From32(system, std::addressof(out_thread_id), thread_handle);
591 591
592 SetReg32(system, 0, Convert<uint32_t>(ret)); 592 SetArg32(args, 0, Convert<uint32_t>(ret));
593 auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id); 593 auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id);
594 SetReg32(system, 1, out_thread_id_scatter[0]); 594 SetArg32(args, 1, out_thread_id_scatter[0]);
595 SetReg32(system, 2, out_thread_id_scatter[1]); 595 SetArg32(args, 2, out_thread_id_scatter[1]);
596} 596}
597 597
598static void SvcWrap_Break64From32(Core::System& system) { 598static void SvcWrap_Break64From32(Core::System& system, std::span<uint64_t, 8> args) {
599 BreakReason break_reason{}; 599 BreakReason break_reason{};
600 uint32_t arg{}; 600 uint32_t arg{};
601 uint32_t size{}; 601 uint32_t size{};
602 602
603 break_reason = Convert<BreakReason>(GetReg32(system, 0)); 603 break_reason = Convert<BreakReason>(GetArg32(args, 0));
604 arg = Convert<uint32_t>(GetReg32(system, 1)); 604 arg = Convert<uint32_t>(GetArg32(args, 1));
605 size = Convert<uint32_t>(GetReg32(system, 2)); 605 size = Convert<uint32_t>(GetArg32(args, 2));
606 606
607 Break64From32(system, break_reason, arg, size); 607 Break64From32(system, break_reason, arg, size);
608} 608}
609 609
610static void SvcWrap_OutputDebugString64From32(Core::System& system) { 610static void SvcWrap_OutputDebugString64From32(Core::System& system, std::span<uint64_t, 8> args) {
611 Result ret{}; 611 Result ret{};
612 612
613 uint32_t debug_str{}; 613 uint32_t debug_str{};
614 uint32_t len{}; 614 uint32_t len{};
615 615
616 debug_str = Convert<uint32_t>(GetReg32(system, 0)); 616 debug_str = Convert<uint32_t>(GetArg32(args, 0));
617 len = Convert<uint32_t>(GetReg32(system, 1)); 617 len = Convert<uint32_t>(GetArg32(args, 1));
618 618
619 ret = OutputDebugString64From32(system, debug_str, len); 619 ret = OutputDebugString64From32(system, debug_str, len);
620 620
621 SetReg32(system, 0, Convert<uint32_t>(ret)); 621 SetArg32(args, 0, Convert<uint32_t>(ret));
622} 622}
623 623
624static void SvcWrap_ReturnFromException64From32(Core::System& system) { 624static void SvcWrap_ReturnFromException64From32(Core::System& system, std::span<uint64_t, 8> args) {
625 Result result{}; 625 Result result{};
626 626
627 result = Convert<Result>(GetReg32(system, 0)); 627 result = Convert<Result>(GetArg32(args, 0));
628 628
629 ReturnFromException64From32(system, result); 629 ReturnFromException64From32(system, result);
630} 630}
631 631
632static void SvcWrap_GetInfo64From32(Core::System& system) { 632static void SvcWrap_GetInfo64From32(Core::System& system, std::span<uint64_t, 8> args) {
633 Result ret{}; 633 Result ret{};
634 634
635 uint64_t out{}; 635 uint64_t out{};
@@ -637,68 +637,68 @@ static void SvcWrap_GetInfo64From32(Core::System& system) {
637 Handle handle{}; 637 Handle handle{};
638 uint64_t info_subtype{}; 638 uint64_t info_subtype{};
639 639
640 info_type = Convert<InfoType>(GetReg32(system, 1)); 640 info_type = Convert<InfoType>(GetArg32(args, 1));
641 handle = Convert<Handle>(GetReg32(system, 2)); 641 handle = Convert<Handle>(GetArg32(args, 2));
642 std::array<uint32_t, 2> info_subtype_gather{}; 642 std::array<uint32_t, 2> info_subtype_gather{};
643 info_subtype_gather[0] = GetReg32(system, 0); 643 info_subtype_gather[0] = GetArg32(args, 0);
644 info_subtype_gather[1] = GetReg32(system, 3); 644 info_subtype_gather[1] = GetArg32(args, 3);
645 info_subtype = Convert<uint64_t>(info_subtype_gather); 645 info_subtype = Convert<uint64_t>(info_subtype_gather);
646 646
647 ret = GetInfo64From32(system, std::addressof(out), info_type, handle, info_subtype); 647 ret = GetInfo64From32(system, std::addressof(out), info_type, handle, info_subtype);
648 648
649 SetReg32(system, 0, Convert<uint32_t>(ret)); 649 SetArg32(args, 0, Convert<uint32_t>(ret));
650 auto out_scatter = Convert<std::array<uint32_t, 2>>(out); 650 auto out_scatter = Convert<std::array<uint32_t, 2>>(out);
651 SetReg32(system, 1, out_scatter[0]); 651 SetArg32(args, 1, out_scatter[0]);
652 SetReg32(system, 2, out_scatter[1]); 652 SetArg32(args, 2, out_scatter[1]);
653} 653}
654 654
655static void SvcWrap_FlushEntireDataCache64From32(Core::System& system) { 655static void SvcWrap_FlushEntireDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) {
656 FlushEntireDataCache64From32(system); 656 FlushEntireDataCache64From32(system);
657} 657}
658 658
659static void SvcWrap_FlushDataCache64From32(Core::System& system) { 659static void SvcWrap_FlushDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) {
660 Result ret{}; 660 Result ret{};
661 661
662 uint32_t address{}; 662 uint32_t address{};
663 uint32_t size{}; 663 uint32_t size{};
664 664
665 address = Convert<uint32_t>(GetReg32(system, 0)); 665 address = Convert<uint32_t>(GetArg32(args, 0));
666 size = Convert<uint32_t>(GetReg32(system, 1)); 666 size = Convert<uint32_t>(GetArg32(args, 1));
667 667
668 ret = FlushDataCache64From32(system, address, size); 668 ret = FlushDataCache64From32(system, address, size);
669 669
670 SetReg32(system, 0, Convert<uint32_t>(ret)); 670 SetArg32(args, 0, Convert<uint32_t>(ret));
671} 671}
672 672
673static void SvcWrap_MapPhysicalMemory64From32(Core::System& system) { 673static void SvcWrap_MapPhysicalMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
674 Result ret{}; 674 Result ret{};
675 675
676 uint32_t address{}; 676 uint32_t address{};
677 uint32_t size{}; 677 uint32_t size{};
678 678
679 address = Convert<uint32_t>(GetReg32(system, 0)); 679 address = Convert<uint32_t>(GetArg32(args, 0));
680 size = Convert<uint32_t>(GetReg32(system, 1)); 680 size = Convert<uint32_t>(GetArg32(args, 1));
681 681
682 ret = MapPhysicalMemory64From32(system, address, size); 682 ret = MapPhysicalMemory64From32(system, address, size);
683 683
684 SetReg32(system, 0, Convert<uint32_t>(ret)); 684 SetArg32(args, 0, Convert<uint32_t>(ret));
685} 685}
686 686
687static void SvcWrap_UnmapPhysicalMemory64From32(Core::System& system) { 687static void SvcWrap_UnmapPhysicalMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
688 Result ret{}; 688 Result ret{};
689 689
690 uint32_t address{}; 690 uint32_t address{};
691 uint32_t size{}; 691 uint32_t size{};
692 692
693 address = Convert<uint32_t>(GetReg32(system, 0)); 693 address = Convert<uint32_t>(GetArg32(args, 0));
694 size = Convert<uint32_t>(GetReg32(system, 1)); 694 size = Convert<uint32_t>(GetArg32(args, 1));
695 695
696 ret = UnmapPhysicalMemory64From32(system, address, size); 696 ret = UnmapPhysicalMemory64From32(system, address, size);
697 697
698 SetReg32(system, 0, Convert<uint32_t>(ret)); 698 SetArg32(args, 0, Convert<uint32_t>(ret));
699} 699}
700 700
701static void SvcWrap_GetDebugFutureThreadInfo64From32(Core::System& system) { 701static void SvcWrap_GetDebugFutureThreadInfo64From32(Core::System& system, std::span<uint64_t, 8> args) {
702 Result ret{}; 702 Result ret{};
703 703
704 ilp32::LastThreadContext out_context{}; 704 ilp32::LastThreadContext out_context{};
@@ -706,26 +706,26 @@ static void SvcWrap_GetDebugFutureThreadInfo64From32(Core::System& system) {
706 Handle debug_handle{}; 706 Handle debug_handle{};
707 int64_t ns{}; 707 int64_t ns{};
708 708
709 debug_handle = Convert<Handle>(GetReg32(system, 2)); 709 debug_handle = Convert<Handle>(GetArg32(args, 2));
710 std::array<uint32_t, 2> ns_gather{}; 710 std::array<uint32_t, 2> ns_gather{};
711 ns_gather[0] = GetReg32(system, 0); 711 ns_gather[0] = GetArg32(args, 0);
712 ns_gather[1] = GetReg32(system, 1); 712 ns_gather[1] = GetArg32(args, 1);
713 ns = Convert<int64_t>(ns_gather); 713 ns = Convert<int64_t>(ns_gather);
714 714
715 ret = GetDebugFutureThreadInfo64From32(system, std::addressof(out_context), std::addressof(out_thread_id), debug_handle, ns); 715 ret = GetDebugFutureThreadInfo64From32(system, std::addressof(out_context), std::addressof(out_thread_id), debug_handle, ns);
716 716
717 SetReg32(system, 0, Convert<uint32_t>(ret)); 717 SetArg32(args, 0, Convert<uint32_t>(ret));
718 auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context); 718 auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context);
719 SetReg32(system, 1, out_context_scatter[0]); 719 SetArg32(args, 1, out_context_scatter[0]);
720 SetReg32(system, 2, out_context_scatter[1]); 720 SetArg32(args, 2, out_context_scatter[1]);
721 SetReg32(system, 3, out_context_scatter[2]); 721 SetArg32(args, 3, out_context_scatter[2]);
722 SetReg32(system, 4, out_context_scatter[3]); 722 SetArg32(args, 4, out_context_scatter[3]);
723 auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id); 723 auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id);
724 SetReg32(system, 5, out_thread_id_scatter[0]); 724 SetArg32(args, 5, out_thread_id_scatter[0]);
725 SetReg32(system, 6, out_thread_id_scatter[1]); 725 SetArg32(args, 6, out_thread_id_scatter[1]);
726} 726}
727 727
728static void SvcWrap_GetLastThreadInfo64From32(Core::System& system) { 728static void SvcWrap_GetLastThreadInfo64From32(Core::System& system, std::span<uint64_t, 8> args) {
729 Result ret{}; 729 Result ret{};
730 730
731 ilp32::LastThreadContext out_context{}; 731 ilp32::LastThreadContext out_context{};
@@ -734,81 +734,81 @@ static void SvcWrap_GetLastThreadInfo64From32(Core::System& system) {
734 734
735 ret = GetLastThreadInfo64From32(system, std::addressof(out_context), std::addressof(out_tls_address), std::addressof(out_flags)); 735 ret = GetLastThreadInfo64From32(system, std::addressof(out_context), std::addressof(out_tls_address), std::addressof(out_flags));
736 736
737 SetReg32(system, 0, Convert<uint32_t>(ret)); 737 SetArg32(args, 0, Convert<uint32_t>(ret));
738 auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context); 738 auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context);
739 SetReg32(system, 1, out_context_scatter[0]); 739 SetArg32(args, 1, out_context_scatter[0]);
740 SetReg32(system, 2, out_context_scatter[1]); 740 SetArg32(args, 2, out_context_scatter[1]);
741 SetReg32(system, 3, out_context_scatter[2]); 741 SetArg32(args, 3, out_context_scatter[2]);
742 SetReg32(system, 4, out_context_scatter[3]); 742 SetArg32(args, 4, out_context_scatter[3]);
743 SetReg32(system, 5, Convert<uint32_t>(out_tls_address)); 743 SetArg32(args, 5, Convert<uint32_t>(out_tls_address));
744 SetReg32(system, 6, Convert<uint32_t>(out_flags)); 744 SetArg32(args, 6, Convert<uint32_t>(out_flags));
745} 745}
746 746
747static void SvcWrap_GetResourceLimitLimitValue64From32(Core::System& system) { 747static void SvcWrap_GetResourceLimitLimitValue64From32(Core::System& system, std::span<uint64_t, 8> args) {
748 Result ret{}; 748 Result ret{};
749 749
750 int64_t out_limit_value{}; 750 int64_t out_limit_value{};
751 Handle resource_limit_handle{}; 751 Handle resource_limit_handle{};
752 LimitableResource which{}; 752 LimitableResource which{};
753 753
754 resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); 754 resource_limit_handle = Convert<Handle>(GetArg32(args, 1));
755 which = Convert<LimitableResource>(GetReg32(system, 2)); 755 which = Convert<LimitableResource>(GetArg32(args, 2));
756 756
757 ret = GetResourceLimitLimitValue64From32(system, std::addressof(out_limit_value), resource_limit_handle, which); 757 ret = GetResourceLimitLimitValue64From32(system, std::addressof(out_limit_value), resource_limit_handle, which);
758 758
759 SetReg32(system, 0, Convert<uint32_t>(ret)); 759 SetArg32(args, 0, Convert<uint32_t>(ret));
760 auto out_limit_value_scatter = Convert<std::array<uint32_t, 2>>(out_limit_value); 760 auto out_limit_value_scatter = Convert<std::array<uint32_t, 2>>(out_limit_value);
761 SetReg32(system, 1, out_limit_value_scatter[0]); 761 SetArg32(args, 1, out_limit_value_scatter[0]);
762 SetReg32(system, 2, out_limit_value_scatter[1]); 762 SetArg32(args, 2, out_limit_value_scatter[1]);
763} 763}
764 764
765static void SvcWrap_GetResourceLimitCurrentValue64From32(Core::System& system) { 765static void SvcWrap_GetResourceLimitCurrentValue64From32(Core::System& system, std::span<uint64_t, 8> args) {
766 Result ret{}; 766 Result ret{};
767 767
768 int64_t out_current_value{}; 768 int64_t out_current_value{};
769 Handle resource_limit_handle{}; 769 Handle resource_limit_handle{};
770 LimitableResource which{}; 770 LimitableResource which{};
771 771
772 resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); 772 resource_limit_handle = Convert<Handle>(GetArg32(args, 1));
773 which = Convert<LimitableResource>(GetReg32(system, 2)); 773 which = Convert<LimitableResource>(GetArg32(args, 2));
774 774
775 ret = GetResourceLimitCurrentValue64From32(system, std::addressof(out_current_value), resource_limit_handle, which); 775 ret = GetResourceLimitCurrentValue64From32(system, std::addressof(out_current_value), resource_limit_handle, which);
776 776
777 SetReg32(system, 0, Convert<uint32_t>(ret)); 777 SetArg32(args, 0, Convert<uint32_t>(ret));
778 auto out_current_value_scatter = Convert<std::array<uint32_t, 2>>(out_current_value); 778 auto out_current_value_scatter = Convert<std::array<uint32_t, 2>>(out_current_value);
779 SetReg32(system, 1, out_current_value_scatter[0]); 779 SetArg32(args, 1, out_current_value_scatter[0]);
780 SetReg32(system, 2, out_current_value_scatter[1]); 780 SetArg32(args, 2, out_current_value_scatter[1]);
781} 781}
782 782
783static void SvcWrap_SetThreadActivity64From32(Core::System& system) { 783static void SvcWrap_SetThreadActivity64From32(Core::System& system, std::span<uint64_t, 8> args) {
784 Result ret{}; 784 Result ret{};
785 785
786 Handle thread_handle{}; 786 Handle thread_handle{};
787 ThreadActivity thread_activity{}; 787 ThreadActivity thread_activity{};
788 788
789 thread_handle = Convert<Handle>(GetReg32(system, 0)); 789 thread_handle = Convert<Handle>(GetArg32(args, 0));
790 thread_activity = Convert<ThreadActivity>(GetReg32(system, 1)); 790 thread_activity = Convert<ThreadActivity>(GetArg32(args, 1));
791 791
792 ret = SetThreadActivity64From32(system, thread_handle, thread_activity); 792 ret = SetThreadActivity64From32(system, thread_handle, thread_activity);
793 793
794 SetReg32(system, 0, Convert<uint32_t>(ret)); 794 SetArg32(args, 0, Convert<uint32_t>(ret));
795} 795}
796 796
797static void SvcWrap_GetThreadContext364From32(Core::System& system) { 797static void SvcWrap_GetThreadContext364From32(Core::System& system, std::span<uint64_t, 8> args) {
798 Result ret{}; 798 Result ret{};
799 799
800 uint32_t out_context{}; 800 uint32_t out_context{};
801 Handle thread_handle{}; 801 Handle thread_handle{};
802 802
803 out_context = Convert<uint32_t>(GetReg32(system, 0)); 803 out_context = Convert<uint32_t>(GetArg32(args, 0));
804 thread_handle = Convert<Handle>(GetReg32(system, 1)); 804 thread_handle = Convert<Handle>(GetArg32(args, 1));
805 805
806 ret = GetThreadContext364From32(system, out_context, thread_handle); 806 ret = GetThreadContext364From32(system, out_context, thread_handle);
807 807
808 SetReg32(system, 0, Convert<uint32_t>(ret)); 808 SetArg32(args, 0, Convert<uint32_t>(ret));
809} 809}
810 810
811static void SvcWrap_WaitForAddress64From32(Core::System& system) { 811static void SvcWrap_WaitForAddress64From32(Core::System& system, std::span<uint64_t, 8> args) {
812 Result ret{}; 812 Result ret{};
813 813
814 uint32_t address{}; 814 uint32_t address{};
@@ -816,20 +816,20 @@ static void SvcWrap_WaitForAddress64From32(Core::System& system) {
816 int32_t value{}; 816 int32_t value{};
817 int64_t timeout_ns{}; 817 int64_t timeout_ns{};
818 818
819 address = Convert<uint32_t>(GetReg32(system, 0)); 819 address = Convert<uint32_t>(GetArg32(args, 0));
820 arb_type = Convert<ArbitrationType>(GetReg32(system, 1)); 820 arb_type = Convert<ArbitrationType>(GetArg32(args, 1));
821 value = Convert<int32_t>(GetReg32(system, 2)); 821 value = Convert<int32_t>(GetArg32(args, 2));
822 std::array<uint32_t, 2> timeout_ns_gather{}; 822 std::array<uint32_t, 2> timeout_ns_gather{};
823 timeout_ns_gather[0] = GetReg32(system, 3); 823 timeout_ns_gather[0] = GetArg32(args, 3);
824 timeout_ns_gather[1] = GetReg32(system, 4); 824 timeout_ns_gather[1] = GetArg32(args, 4);
825 timeout_ns = Convert<int64_t>(timeout_ns_gather); 825 timeout_ns = Convert<int64_t>(timeout_ns_gather);
826 826
827 ret = WaitForAddress64From32(system, address, arb_type, value, timeout_ns); 827 ret = WaitForAddress64From32(system, address, arb_type, value, timeout_ns);
828 828
829 SetReg32(system, 0, Convert<uint32_t>(ret)); 829 SetArg32(args, 0, Convert<uint32_t>(ret));
830} 830}
831 831
832static void SvcWrap_SignalToAddress64From32(Core::System& system) { 832static void SvcWrap_SignalToAddress64From32(Core::System& system, std::span<uint64_t, 8> args) {
833 Result ret{}; 833 Result ret{};
834 834
835 uint32_t address{}; 835 uint32_t address{};
@@ -837,53 +837,53 @@ static void SvcWrap_SignalToAddress64From32(Core::System& system) {
837 int32_t value{}; 837 int32_t value{};
838 int32_t count{}; 838 int32_t count{};
839 839
840 address = Convert<uint32_t>(GetReg32(system, 0)); 840 address = Convert<uint32_t>(GetArg32(args, 0));
841 signal_type = Convert<SignalType>(GetReg32(system, 1)); 841 signal_type = Convert<SignalType>(GetArg32(args, 1));
842 value = Convert<int32_t>(GetReg32(system, 2)); 842 value = Convert<int32_t>(GetArg32(args, 2));
843 count = Convert<int32_t>(GetReg32(system, 3)); 843 count = Convert<int32_t>(GetArg32(args, 3));
844 844
845 ret = SignalToAddress64From32(system, address, signal_type, value, count); 845 ret = SignalToAddress64From32(system, address, signal_type, value, count);
846 846
847 SetReg32(system, 0, Convert<uint32_t>(ret)); 847 SetArg32(args, 0, Convert<uint32_t>(ret));
848} 848}
849 849
850static void SvcWrap_SynchronizePreemptionState64From32(Core::System& system) { 850static void SvcWrap_SynchronizePreemptionState64From32(Core::System& system, std::span<uint64_t, 8> args) {
851 SynchronizePreemptionState64From32(system); 851 SynchronizePreemptionState64From32(system);
852} 852}
853 853
854static void SvcWrap_GetResourceLimitPeakValue64From32(Core::System& system) { 854static void SvcWrap_GetResourceLimitPeakValue64From32(Core::System& system, std::span<uint64_t, 8> args) {
855 Result ret{}; 855 Result ret{};
856 856
857 int64_t out_peak_value{}; 857 int64_t out_peak_value{};
858 Handle resource_limit_handle{}; 858 Handle resource_limit_handle{};
859 LimitableResource which{}; 859 LimitableResource which{};
860 860
861 resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); 861 resource_limit_handle = Convert<Handle>(GetArg32(args, 1));
862 which = Convert<LimitableResource>(GetReg32(system, 2)); 862 which = Convert<LimitableResource>(GetArg32(args, 2));
863 863
864 ret = GetResourceLimitPeakValue64From32(system, std::addressof(out_peak_value), resource_limit_handle, which); 864 ret = GetResourceLimitPeakValue64From32(system, std::addressof(out_peak_value), resource_limit_handle, which);
865 865
866 SetReg32(system, 0, Convert<uint32_t>(ret)); 866 SetArg32(args, 0, Convert<uint32_t>(ret));
867 auto out_peak_value_scatter = Convert<std::array<uint32_t, 2>>(out_peak_value); 867 auto out_peak_value_scatter = Convert<std::array<uint32_t, 2>>(out_peak_value);
868 SetReg32(system, 1, out_peak_value_scatter[0]); 868 SetArg32(args, 1, out_peak_value_scatter[0]);
869 SetReg32(system, 2, out_peak_value_scatter[1]); 869 SetArg32(args, 2, out_peak_value_scatter[1]);
870} 870}
871 871
872static void SvcWrap_CreateIoPool64From32(Core::System& system) { 872static void SvcWrap_CreateIoPool64From32(Core::System& system, std::span<uint64_t, 8> args) {
873 Result ret{}; 873 Result ret{};
874 874
875 Handle out_handle{}; 875 Handle out_handle{};
876 IoPoolType which{}; 876 IoPoolType which{};
877 877
878 which = Convert<IoPoolType>(GetReg32(system, 1)); 878 which = Convert<IoPoolType>(GetArg32(args, 1));
879 879
880 ret = CreateIoPool64From32(system, std::addressof(out_handle), which); 880 ret = CreateIoPool64From32(system, std::addressof(out_handle), which);
881 881
882 SetReg32(system, 0, Convert<uint32_t>(ret)); 882 SetArg32(args, 0, Convert<uint32_t>(ret));
883 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 883 SetArg32(args, 1, Convert<uint32_t>(out_handle));
884} 884}
885 885
886static void SvcWrap_CreateIoRegion64From32(Core::System& system) { 886static void SvcWrap_CreateIoRegion64From32(Core::System& system, std::span<uint64_t, 8> args) {
887 Result ret{}; 887 Result ret{};
888 888
889 Handle out_handle{}; 889 Handle out_handle{};
@@ -893,53 +893,53 @@ static void SvcWrap_CreateIoRegion64From32(Core::System& system) {
893 MemoryMapping mapping{}; 893 MemoryMapping mapping{};
894 MemoryPermission perm{}; 894 MemoryPermission perm{};
895 895
896 io_pool = Convert<Handle>(GetReg32(system, 1)); 896 io_pool = Convert<Handle>(GetArg32(args, 1));
897 std::array<uint32_t, 2> physical_address_gather{}; 897 std::array<uint32_t, 2> physical_address_gather{};
898 physical_address_gather[0] = GetReg32(system, 2); 898 physical_address_gather[0] = GetArg32(args, 2);
899 physical_address_gather[1] = GetReg32(system, 3); 899 physical_address_gather[1] = GetArg32(args, 3);
900 physical_address = Convert<uint64_t>(physical_address_gather); 900 physical_address = Convert<uint64_t>(physical_address_gather);
901 size = Convert<uint32_t>(GetReg32(system, 0)); 901 size = Convert<uint32_t>(GetArg32(args, 0));
902 mapping = Convert<MemoryMapping>(GetReg32(system, 4)); 902 mapping = Convert<MemoryMapping>(GetArg32(args, 4));
903 perm = Convert<MemoryPermission>(GetReg32(system, 5)); 903 perm = Convert<MemoryPermission>(GetArg32(args, 5));
904 904
905 ret = CreateIoRegion64From32(system, std::addressof(out_handle), io_pool, physical_address, size, mapping, perm); 905 ret = CreateIoRegion64From32(system, std::addressof(out_handle), io_pool, physical_address, size, mapping, perm);
906 906
907 SetReg32(system, 0, Convert<uint32_t>(ret)); 907 SetArg32(args, 0, Convert<uint32_t>(ret));
908 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 908 SetArg32(args, 1, Convert<uint32_t>(out_handle));
909} 909}
910 910
911static void SvcWrap_KernelDebug64From32(Core::System& system) { 911static void SvcWrap_KernelDebug64From32(Core::System& system, std::span<uint64_t, 8> args) {
912 KernelDebugType kern_debug_type{}; 912 KernelDebugType kern_debug_type{};
913 uint64_t arg0{}; 913 uint64_t arg0{};
914 uint64_t arg1{}; 914 uint64_t arg1{};
915 uint64_t arg2{}; 915 uint64_t arg2{};
916 916
917 kern_debug_type = Convert<KernelDebugType>(GetReg32(system, 0)); 917 kern_debug_type = Convert<KernelDebugType>(GetArg32(args, 0));
918 std::array<uint32_t, 2> arg0_gather{}; 918 std::array<uint32_t, 2> arg0_gather{};
919 arg0_gather[0] = GetReg32(system, 2); 919 arg0_gather[0] = GetArg32(args, 2);
920 arg0_gather[1] = GetReg32(system, 3); 920 arg0_gather[1] = GetArg32(args, 3);
921 arg0 = Convert<uint64_t>(arg0_gather); 921 arg0 = Convert<uint64_t>(arg0_gather);
922 std::array<uint32_t, 2> arg1_gather{}; 922 std::array<uint32_t, 2> arg1_gather{};
923 arg1_gather[0] = GetReg32(system, 1); 923 arg1_gather[0] = GetArg32(args, 1);
924 arg1_gather[1] = GetReg32(system, 4); 924 arg1_gather[1] = GetArg32(args, 4);
925 arg1 = Convert<uint64_t>(arg1_gather); 925 arg1 = Convert<uint64_t>(arg1_gather);
926 std::array<uint32_t, 2> arg2_gather{}; 926 std::array<uint32_t, 2> arg2_gather{};
927 arg2_gather[0] = GetReg32(system, 5); 927 arg2_gather[0] = GetArg32(args, 5);
928 arg2_gather[1] = GetReg32(system, 6); 928 arg2_gather[1] = GetArg32(args, 6);
929 arg2 = Convert<uint64_t>(arg2_gather); 929 arg2 = Convert<uint64_t>(arg2_gather);
930 930
931 KernelDebug64From32(system, kern_debug_type, arg0, arg1, arg2); 931 KernelDebug64From32(system, kern_debug_type, arg0, arg1, arg2);
932} 932}
933 933
934static void SvcWrap_ChangeKernelTraceState64From32(Core::System& system) { 934static void SvcWrap_ChangeKernelTraceState64From32(Core::System& system, std::span<uint64_t, 8> args) {
935 KernelTraceState kern_trace_state{}; 935 KernelTraceState kern_trace_state{};
936 936
937 kern_trace_state = Convert<KernelTraceState>(GetReg32(system, 0)); 937 kern_trace_state = Convert<KernelTraceState>(GetArg32(args, 0));
938 938
939 ChangeKernelTraceState64From32(system, kern_trace_state); 939 ChangeKernelTraceState64From32(system, kern_trace_state);
940} 940}
941 941
942static void SvcWrap_CreateSession64From32(Core::System& system) { 942static void SvcWrap_CreateSession64From32(Core::System& system, std::span<uint64_t, 8> args) {
943 Result ret{}; 943 Result ret{};
944 944
945 Handle out_server_session_handle{}; 945 Handle out_server_session_handle{};
@@ -947,31 +947,31 @@ static void SvcWrap_CreateSession64From32(Core::System& system) {
947 bool is_light{}; 947 bool is_light{};
948 uint32_t name{}; 948 uint32_t name{};
949 949
950 is_light = Convert<bool>(GetReg32(system, 2)); 950 is_light = Convert<bool>(GetArg32(args, 2));
951 name = Convert<uint32_t>(GetReg32(system, 3)); 951 name = Convert<uint32_t>(GetArg32(args, 3));
952 952
953 ret = CreateSession64From32(system, std::addressof(out_server_session_handle), std::addressof(out_client_session_handle), is_light, name); 953 ret = CreateSession64From32(system, std::addressof(out_server_session_handle), std::addressof(out_client_session_handle), is_light, name);
954 954
955 SetReg32(system, 0, Convert<uint32_t>(ret)); 955 SetArg32(args, 0, Convert<uint32_t>(ret));
956 SetReg32(system, 1, Convert<uint32_t>(out_server_session_handle)); 956 SetArg32(args, 1, Convert<uint32_t>(out_server_session_handle));
957 SetReg32(system, 2, Convert<uint32_t>(out_client_session_handle)); 957 SetArg32(args, 2, Convert<uint32_t>(out_client_session_handle));
958} 958}
959 959
960static void SvcWrap_AcceptSession64From32(Core::System& system) { 960static void SvcWrap_AcceptSession64From32(Core::System& system, std::span<uint64_t, 8> args) {
961 Result ret{}; 961 Result ret{};
962 962
963 Handle out_handle{}; 963 Handle out_handle{};
964 Handle port{}; 964 Handle port{};
965 965
966 port = Convert<Handle>(GetReg32(system, 1)); 966 port = Convert<Handle>(GetArg32(args, 1));
967 967
968 ret = AcceptSession64From32(system, std::addressof(out_handle), port); 968 ret = AcceptSession64From32(system, std::addressof(out_handle), port);
969 969
970 SetReg32(system, 0, Convert<uint32_t>(ret)); 970 SetArg32(args, 0, Convert<uint32_t>(ret));
971 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 971 SetArg32(args, 1, Convert<uint32_t>(out_handle));
972} 972}
973 973
974static void SvcWrap_ReplyAndReceive64From32(Core::System& system) { 974static void SvcWrap_ReplyAndReceive64From32(Core::System& system, std::span<uint64_t, 8> args) {
975 Result ret{}; 975 Result ret{};
976 976
977 int32_t out_index{}; 977 int32_t out_index{};
@@ -980,21 +980,21 @@ static void SvcWrap_ReplyAndReceive64From32(Core::System& system) {
980 Handle reply_target{}; 980 Handle reply_target{};
981 int64_t timeout_ns{}; 981 int64_t timeout_ns{};
982 982
983 handles = Convert<uint32_t>(GetReg32(system, 1)); 983 handles = Convert<uint32_t>(GetArg32(args, 1));
984 num_handles = Convert<int32_t>(GetReg32(system, 2)); 984 num_handles = Convert<int32_t>(GetArg32(args, 2));
985 reply_target = Convert<Handle>(GetReg32(system, 3)); 985 reply_target = Convert<Handle>(GetArg32(args, 3));
986 std::array<uint32_t, 2> timeout_ns_gather{}; 986 std::array<uint32_t, 2> timeout_ns_gather{};
987 timeout_ns_gather[0] = GetReg32(system, 0); 987 timeout_ns_gather[0] = GetArg32(args, 0);
988 timeout_ns_gather[1] = GetReg32(system, 4); 988 timeout_ns_gather[1] = GetArg32(args, 4);
989 timeout_ns = Convert<int64_t>(timeout_ns_gather); 989 timeout_ns = Convert<int64_t>(timeout_ns_gather);
990 990
991 ret = ReplyAndReceive64From32(system, std::addressof(out_index), handles, num_handles, reply_target, timeout_ns); 991 ret = ReplyAndReceive64From32(system, std::addressof(out_index), handles, num_handles, reply_target, timeout_ns);
992 992
993 SetReg32(system, 0, Convert<uint32_t>(ret)); 993 SetArg32(args, 0, Convert<uint32_t>(ret));
994 SetReg32(system, 1, Convert<uint32_t>(out_index)); 994 SetArg32(args, 1, Convert<uint32_t>(out_index));
995} 995}
996 996
997static void SvcWrap_ReplyAndReceiveWithUserBuffer64From32(Core::System& system) { 997static void SvcWrap_ReplyAndReceiveWithUserBuffer64From32(Core::System& system, std::span<uint64_t, 8> args) {
998 Result ret{}; 998 Result ret{};
999 999
1000 int32_t out_index{}; 1000 int32_t out_index{};
@@ -1005,23 +1005,23 @@ static void SvcWrap_ReplyAndReceiveWithUserBuffer64From32(Core::System& system)
1005 Handle reply_target{}; 1005 Handle reply_target{};
1006 int64_t timeout_ns{}; 1006 int64_t timeout_ns{};
1007 1007
1008 message_buffer = Convert<uint32_t>(GetReg32(system, 1)); 1008 message_buffer = Convert<uint32_t>(GetArg32(args, 1));
1009 message_buffer_size = Convert<uint32_t>(GetReg32(system, 2)); 1009 message_buffer_size = Convert<uint32_t>(GetArg32(args, 2));
1010 handles = Convert<uint32_t>(GetReg32(system, 3)); 1010 handles = Convert<uint32_t>(GetArg32(args, 3));
1011 num_handles = Convert<int32_t>(GetReg32(system, 0)); 1011 num_handles = Convert<int32_t>(GetArg32(args, 0));
1012 reply_target = Convert<Handle>(GetReg32(system, 4)); 1012 reply_target = Convert<Handle>(GetArg32(args, 4));
1013 std::array<uint32_t, 2> timeout_ns_gather{}; 1013 std::array<uint32_t, 2> timeout_ns_gather{};
1014 timeout_ns_gather[0] = GetReg32(system, 5); 1014 timeout_ns_gather[0] = GetArg32(args, 5);
1015 timeout_ns_gather[1] = GetReg32(system, 6); 1015 timeout_ns_gather[1] = GetArg32(args, 6);
1016 timeout_ns = Convert<int64_t>(timeout_ns_gather); 1016 timeout_ns = Convert<int64_t>(timeout_ns_gather);
1017 1017
1018 ret = ReplyAndReceiveWithUserBuffer64From32(system, std::addressof(out_index), message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns); 1018 ret = ReplyAndReceiveWithUserBuffer64From32(system, std::addressof(out_index), message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns);
1019 1019
1020 SetReg32(system, 0, Convert<uint32_t>(ret)); 1020 SetArg32(args, 0, Convert<uint32_t>(ret));
1021 SetReg32(system, 1, Convert<uint32_t>(out_index)); 1021 SetArg32(args, 1, Convert<uint32_t>(out_index));
1022} 1022}
1023 1023
1024static void SvcWrap_CreateEvent64From32(Core::System& system) { 1024static void SvcWrap_CreateEvent64From32(Core::System& system, std::span<uint64_t, 8> args) {
1025 Result ret{}; 1025 Result ret{};
1026 1026
1027 Handle out_write_handle{}; 1027 Handle out_write_handle{};
@@ -1029,12 +1029,12 @@ static void SvcWrap_CreateEvent64From32(Core::System& system) {
1029 1029
1030 ret = CreateEvent64From32(system, std::addressof(out_write_handle), std::addressof(out_read_handle)); 1030 ret = CreateEvent64From32(system, std::addressof(out_write_handle), std::addressof(out_read_handle));
1031 1031
1032 SetReg32(system, 0, Convert<uint32_t>(ret)); 1032 SetArg32(args, 0, Convert<uint32_t>(ret));
1033 SetReg32(system, 1, Convert<uint32_t>(out_write_handle)); 1033 SetArg32(args, 1, Convert<uint32_t>(out_write_handle));
1034 SetReg32(system, 2, Convert<uint32_t>(out_read_handle)); 1034 SetArg32(args, 2, Convert<uint32_t>(out_read_handle));
1035} 1035}
1036 1036
1037static void SvcWrap_MapIoRegion64From32(Core::System& system) { 1037static void SvcWrap_MapIoRegion64From32(Core::System& system, std::span<uint64_t, 8> args) {
1038 Result ret{}; 1038 Result ret{};
1039 1039
1040 Handle io_region{}; 1040 Handle io_region{};
@@ -1042,89 +1042,89 @@ static void SvcWrap_MapIoRegion64From32(Core::System& system) {
1042 uint32_t size{}; 1042 uint32_t size{};
1043 MemoryPermission perm{}; 1043 MemoryPermission perm{};
1044 1044
1045 io_region = Convert<Handle>(GetReg32(system, 0)); 1045 io_region = Convert<Handle>(GetArg32(args, 0));
1046 address = Convert<uint32_t>(GetReg32(system, 1)); 1046 address = Convert<uint32_t>(GetArg32(args, 1));
1047 size = Convert<uint32_t>(GetReg32(system, 2)); 1047 size = Convert<uint32_t>(GetArg32(args, 2));
1048 perm = Convert<MemoryPermission>(GetReg32(system, 3)); 1048 perm = Convert<MemoryPermission>(GetArg32(args, 3));
1049 1049
1050 ret = MapIoRegion64From32(system, io_region, address, size, perm); 1050 ret = MapIoRegion64From32(system, io_region, address, size, perm);
1051 1051
1052 SetReg32(system, 0, Convert<uint32_t>(ret)); 1052 SetArg32(args, 0, Convert<uint32_t>(ret));
1053} 1053}
1054 1054
1055static void SvcWrap_UnmapIoRegion64From32(Core::System& system) { 1055static void SvcWrap_UnmapIoRegion64From32(Core::System& system, std::span<uint64_t, 8> args) {
1056 Result ret{}; 1056 Result ret{};
1057 1057
1058 Handle io_region{}; 1058 Handle io_region{};
1059 uint32_t address{}; 1059 uint32_t address{};
1060 uint32_t size{}; 1060 uint32_t size{};
1061 1061
1062 io_region = Convert<Handle>(GetReg32(system, 0)); 1062 io_region = Convert<Handle>(GetArg32(args, 0));
1063 address = Convert<uint32_t>(GetReg32(system, 1)); 1063 address = Convert<uint32_t>(GetArg32(args, 1));
1064 size = Convert<uint32_t>(GetReg32(system, 2)); 1064 size = Convert<uint32_t>(GetArg32(args, 2));
1065 1065
1066 ret = UnmapIoRegion64From32(system, io_region, address, size); 1066 ret = UnmapIoRegion64From32(system, io_region, address, size);
1067 1067
1068 SetReg32(system, 0, Convert<uint32_t>(ret)); 1068 SetArg32(args, 0, Convert<uint32_t>(ret));
1069} 1069}
1070 1070
1071static void SvcWrap_MapPhysicalMemoryUnsafe64From32(Core::System& system) { 1071static void SvcWrap_MapPhysicalMemoryUnsafe64From32(Core::System& system, std::span<uint64_t, 8> args) {
1072 Result ret{}; 1072 Result ret{};
1073 1073
1074 uint32_t address{}; 1074 uint32_t address{};
1075 uint32_t size{}; 1075 uint32_t size{};
1076 1076
1077 address = Convert<uint32_t>(GetReg32(system, 0)); 1077 address = Convert<uint32_t>(GetArg32(args, 0));
1078 size = Convert<uint32_t>(GetReg32(system, 1)); 1078 size = Convert<uint32_t>(GetArg32(args, 1));
1079 1079
1080 ret = MapPhysicalMemoryUnsafe64From32(system, address, size); 1080 ret = MapPhysicalMemoryUnsafe64From32(system, address, size);
1081 1081
1082 SetReg32(system, 0, Convert<uint32_t>(ret)); 1082 SetArg32(args, 0, Convert<uint32_t>(ret));
1083} 1083}
1084 1084
1085static void SvcWrap_UnmapPhysicalMemoryUnsafe64From32(Core::System& system) { 1085static void SvcWrap_UnmapPhysicalMemoryUnsafe64From32(Core::System& system, std::span<uint64_t, 8> args) {
1086 Result ret{}; 1086 Result ret{};
1087 1087
1088 uint32_t address{}; 1088 uint32_t address{};
1089 uint32_t size{}; 1089 uint32_t size{};
1090 1090
1091 address = Convert<uint32_t>(GetReg32(system, 0)); 1091 address = Convert<uint32_t>(GetArg32(args, 0));
1092 size = Convert<uint32_t>(GetReg32(system, 1)); 1092 size = Convert<uint32_t>(GetArg32(args, 1));
1093 1093
1094 ret = UnmapPhysicalMemoryUnsafe64From32(system, address, size); 1094 ret = UnmapPhysicalMemoryUnsafe64From32(system, address, size);
1095 1095
1096 SetReg32(system, 0, Convert<uint32_t>(ret)); 1096 SetArg32(args, 0, Convert<uint32_t>(ret));
1097} 1097}
1098 1098
1099static void SvcWrap_SetUnsafeLimit64From32(Core::System& system) { 1099static void SvcWrap_SetUnsafeLimit64From32(Core::System& system, std::span<uint64_t, 8> args) {
1100 Result ret{}; 1100 Result ret{};
1101 1101
1102 uint32_t limit{}; 1102 uint32_t limit{};
1103 1103
1104 limit = Convert<uint32_t>(GetReg32(system, 0)); 1104 limit = Convert<uint32_t>(GetArg32(args, 0));
1105 1105
1106 ret = SetUnsafeLimit64From32(system, limit); 1106 ret = SetUnsafeLimit64From32(system, limit);
1107 1107
1108 SetReg32(system, 0, Convert<uint32_t>(ret)); 1108 SetArg32(args, 0, Convert<uint32_t>(ret));
1109} 1109}
1110 1110
1111static void SvcWrap_CreateCodeMemory64From32(Core::System& system) { 1111static void SvcWrap_CreateCodeMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1112 Result ret{}; 1112 Result ret{};
1113 1113
1114 Handle out_handle{}; 1114 Handle out_handle{};
1115 uint32_t address{}; 1115 uint32_t address{};
1116 uint32_t size{}; 1116 uint32_t size{};
1117 1117
1118 address = Convert<uint32_t>(GetReg32(system, 1)); 1118 address = Convert<uint32_t>(GetArg32(args, 1));
1119 size = Convert<uint32_t>(GetReg32(system, 2)); 1119 size = Convert<uint32_t>(GetArg32(args, 2));
1120 1120
1121 ret = CreateCodeMemory64From32(system, std::addressof(out_handle), address, size); 1121 ret = CreateCodeMemory64From32(system, std::addressof(out_handle), address, size);
1122 1122
1123 SetReg32(system, 0, Convert<uint32_t>(ret)); 1123 SetArg32(args, 0, Convert<uint32_t>(ret));
1124 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 1124 SetArg32(args, 1, Convert<uint32_t>(out_handle));
1125} 1125}
1126 1126
1127static void SvcWrap_ControlCodeMemory64From32(Core::System& system) { 1127static void SvcWrap_ControlCodeMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1128 Result ret{}; 1128 Result ret{};
1129 1129
1130 Handle code_memory_handle{}; 1130 Handle code_memory_handle{};
@@ -1133,28 +1133,28 @@ static void SvcWrap_ControlCodeMemory64From32(Core::System& system) {
1133 uint64_t size{}; 1133 uint64_t size{};
1134 MemoryPermission perm{}; 1134 MemoryPermission perm{};
1135 1135
1136 code_memory_handle = Convert<Handle>(GetReg32(system, 0)); 1136 code_memory_handle = Convert<Handle>(GetArg32(args, 0));
1137 operation = Convert<CodeMemoryOperation>(GetReg32(system, 1)); 1137 operation = Convert<CodeMemoryOperation>(GetArg32(args, 1));
1138 std::array<uint32_t, 2> address_gather{}; 1138 std::array<uint32_t, 2> address_gather{};
1139 address_gather[0] = GetReg32(system, 2); 1139 address_gather[0] = GetArg32(args, 2);
1140 address_gather[1] = GetReg32(system, 3); 1140 address_gather[1] = GetArg32(args, 3);
1141 address = Convert<uint64_t>(address_gather); 1141 address = Convert<uint64_t>(address_gather);
1142 std::array<uint32_t, 2> size_gather{}; 1142 std::array<uint32_t, 2> size_gather{};
1143 size_gather[0] = GetReg32(system, 4); 1143 size_gather[0] = GetArg32(args, 4);
1144 size_gather[1] = GetReg32(system, 5); 1144 size_gather[1] = GetArg32(args, 5);
1145 size = Convert<uint64_t>(size_gather); 1145 size = Convert<uint64_t>(size_gather);
1146 perm = Convert<MemoryPermission>(GetReg32(system, 6)); 1146 perm = Convert<MemoryPermission>(GetArg32(args, 6));
1147 1147
1148 ret = ControlCodeMemory64From32(system, code_memory_handle, operation, address, size, perm); 1148 ret = ControlCodeMemory64From32(system, code_memory_handle, operation, address, size, perm);
1149 1149
1150 SetReg32(system, 0, Convert<uint32_t>(ret)); 1150 SetArg32(args, 0, Convert<uint32_t>(ret));
1151} 1151}
1152 1152
1153static void SvcWrap_SleepSystem64From32(Core::System& system) { 1153static void SvcWrap_SleepSystem64From32(Core::System& system, std::span<uint64_t, 8> args) {
1154 SleepSystem64From32(system); 1154 SleepSystem64From32(system);
1155} 1155}
1156 1156
1157static void SvcWrap_ReadWriteRegister64From32(Core::System& system) { 1157static void SvcWrap_ReadWriteRegister64From32(Core::System& system, std::span<uint64_t, 8> args) {
1158 Result ret{}; 1158 Result ret{};
1159 1159
1160 uint32_t out_value{}; 1160 uint32_t out_value{};
@@ -1163,33 +1163,33 @@ static void SvcWrap_ReadWriteRegister64From32(Core::System& system) {
1163 uint32_t value{}; 1163 uint32_t value{};
1164 1164
1165 std::array<uint32_t, 2> address_gather{}; 1165 std::array<uint32_t, 2> address_gather{};
1166 address_gather[0] = GetReg32(system, 2); 1166 address_gather[0] = GetArg32(args, 2);
1167 address_gather[1] = GetReg32(system, 3); 1167 address_gather[1] = GetArg32(args, 3);
1168 address = Convert<uint64_t>(address_gather); 1168 address = Convert<uint64_t>(address_gather);
1169 mask = Convert<uint32_t>(GetReg32(system, 0)); 1169 mask = Convert<uint32_t>(GetArg32(args, 0));
1170 value = Convert<uint32_t>(GetReg32(system, 1)); 1170 value = Convert<uint32_t>(GetArg32(args, 1));
1171 1171
1172 ret = ReadWriteRegister64From32(system, std::addressof(out_value), address, mask, value); 1172 ret = ReadWriteRegister64From32(system, std::addressof(out_value), address, mask, value);
1173 1173
1174 SetReg32(system, 0, Convert<uint32_t>(ret)); 1174 SetArg32(args, 0, Convert<uint32_t>(ret));
1175 SetReg32(system, 1, Convert<uint32_t>(out_value)); 1175 SetArg32(args, 1, Convert<uint32_t>(out_value));
1176} 1176}
1177 1177
1178static void SvcWrap_SetProcessActivity64From32(Core::System& system) { 1178static void SvcWrap_SetProcessActivity64From32(Core::System& system, std::span<uint64_t, 8> args) {
1179 Result ret{}; 1179 Result ret{};
1180 1180
1181 Handle process_handle{}; 1181 Handle process_handle{};
1182 ProcessActivity process_activity{}; 1182 ProcessActivity process_activity{};
1183 1183
1184 process_handle = Convert<Handle>(GetReg32(system, 0)); 1184 process_handle = Convert<Handle>(GetArg32(args, 0));
1185 process_activity = Convert<ProcessActivity>(GetReg32(system, 1)); 1185 process_activity = Convert<ProcessActivity>(GetArg32(args, 1));
1186 1186
1187 ret = SetProcessActivity64From32(system, process_handle, process_activity); 1187 ret = SetProcessActivity64From32(system, process_handle, process_activity);
1188 1188
1189 SetReg32(system, 0, Convert<uint32_t>(ret)); 1189 SetArg32(args, 0, Convert<uint32_t>(ret));
1190} 1190}
1191 1191
1192static void SvcWrap_CreateSharedMemory64From32(Core::System& system) { 1192static void SvcWrap_CreateSharedMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1193 Result ret{}; 1193 Result ret{};
1194 1194
1195 Handle out_handle{}; 1195 Handle out_handle{};
@@ -1197,17 +1197,17 @@ static void SvcWrap_CreateSharedMemory64From32(Core::System& system) {
1197 MemoryPermission owner_perm{}; 1197 MemoryPermission owner_perm{};
1198 MemoryPermission remote_perm{}; 1198 MemoryPermission remote_perm{};
1199 1199
1200 size = Convert<uint32_t>(GetReg32(system, 1)); 1200 size = Convert<uint32_t>(GetArg32(args, 1));
1201 owner_perm = Convert<MemoryPermission>(GetReg32(system, 2)); 1201 owner_perm = Convert<MemoryPermission>(GetArg32(args, 2));
1202 remote_perm = Convert<MemoryPermission>(GetReg32(system, 3)); 1202 remote_perm = Convert<MemoryPermission>(GetArg32(args, 3));
1203 1203
1204 ret = CreateSharedMemory64From32(system, std::addressof(out_handle), size, owner_perm, remote_perm); 1204 ret = CreateSharedMemory64From32(system, std::addressof(out_handle), size, owner_perm, remote_perm);
1205 1205
1206 SetReg32(system, 0, Convert<uint32_t>(ret)); 1206 SetArg32(args, 0, Convert<uint32_t>(ret));
1207 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 1207 SetArg32(args, 1, Convert<uint32_t>(out_handle));
1208} 1208}
1209 1209
1210static void SvcWrap_MapTransferMemory64From32(Core::System& system) { 1210static void SvcWrap_MapTransferMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1211 Result ret{}; 1211 Result ret{};
1212 1212
1213 Handle trmem_handle{}; 1213 Handle trmem_handle{};
@@ -1215,67 +1215,67 @@ static void SvcWrap_MapTransferMemory64From32(Core::System& system) {
1215 uint32_t size{}; 1215 uint32_t size{};
1216 MemoryPermission owner_perm{}; 1216 MemoryPermission owner_perm{};
1217 1217
1218 trmem_handle = Convert<Handle>(GetReg32(system, 0)); 1218 trmem_handle = Convert<Handle>(GetArg32(args, 0));
1219 address = Convert<uint32_t>(GetReg32(system, 1)); 1219 address = Convert<uint32_t>(GetArg32(args, 1));
1220 size = Convert<uint32_t>(GetReg32(system, 2)); 1220 size = Convert<uint32_t>(GetArg32(args, 2));
1221 owner_perm = Convert<MemoryPermission>(GetReg32(system, 3)); 1221 owner_perm = Convert<MemoryPermission>(GetArg32(args, 3));
1222 1222
1223 ret = MapTransferMemory64From32(system, trmem_handle, address, size, owner_perm); 1223 ret = MapTransferMemory64From32(system, trmem_handle, address, size, owner_perm);
1224 1224
1225 SetReg32(system, 0, Convert<uint32_t>(ret)); 1225 SetArg32(args, 0, Convert<uint32_t>(ret));
1226} 1226}
1227 1227
1228static void SvcWrap_UnmapTransferMemory64From32(Core::System& system) { 1228static void SvcWrap_UnmapTransferMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1229 Result ret{}; 1229 Result ret{};
1230 1230
1231 Handle trmem_handle{}; 1231 Handle trmem_handle{};
1232 uint32_t address{}; 1232 uint32_t address{};
1233 uint32_t size{}; 1233 uint32_t size{};
1234 1234
1235 trmem_handle = Convert<Handle>(GetReg32(system, 0)); 1235 trmem_handle = Convert<Handle>(GetArg32(args, 0));
1236 address = Convert<uint32_t>(GetReg32(system, 1)); 1236 address = Convert<uint32_t>(GetArg32(args, 1));
1237 size = Convert<uint32_t>(GetReg32(system, 2)); 1237 size = Convert<uint32_t>(GetArg32(args, 2));
1238 1238
1239 ret = UnmapTransferMemory64From32(system, trmem_handle, address, size); 1239 ret = UnmapTransferMemory64From32(system, trmem_handle, address, size);
1240 1240
1241 SetReg32(system, 0, Convert<uint32_t>(ret)); 1241 SetArg32(args, 0, Convert<uint32_t>(ret));
1242} 1242}
1243 1243
1244static void SvcWrap_CreateInterruptEvent64From32(Core::System& system) { 1244static void SvcWrap_CreateInterruptEvent64From32(Core::System& system, std::span<uint64_t, 8> args) {
1245 Result ret{}; 1245 Result ret{};
1246 1246
1247 Handle out_read_handle{}; 1247 Handle out_read_handle{};
1248 int32_t interrupt_id{}; 1248 int32_t interrupt_id{};
1249 InterruptType interrupt_type{}; 1249 InterruptType interrupt_type{};
1250 1250
1251 interrupt_id = Convert<int32_t>(GetReg32(system, 1)); 1251 interrupt_id = Convert<int32_t>(GetArg32(args, 1));
1252 interrupt_type = Convert<InterruptType>(GetReg32(system, 2)); 1252 interrupt_type = Convert<InterruptType>(GetArg32(args, 2));
1253 1253
1254 ret = CreateInterruptEvent64From32(system, std::addressof(out_read_handle), interrupt_id, interrupt_type); 1254 ret = CreateInterruptEvent64From32(system, std::addressof(out_read_handle), interrupt_id, interrupt_type);
1255 1255
1256 SetReg32(system, 0, Convert<uint32_t>(ret)); 1256 SetArg32(args, 0, Convert<uint32_t>(ret));
1257 SetReg32(system, 1, Convert<uint32_t>(out_read_handle)); 1257 SetArg32(args, 1, Convert<uint32_t>(out_read_handle));
1258} 1258}
1259 1259
1260static void SvcWrap_QueryPhysicalAddress64From32(Core::System& system) { 1260static void SvcWrap_QueryPhysicalAddress64From32(Core::System& system, std::span<uint64_t, 8> args) {
1261 Result ret{}; 1261 Result ret{};
1262 1262
1263 ilp32::PhysicalMemoryInfo out_info{}; 1263 ilp32::PhysicalMemoryInfo out_info{};
1264 uint32_t address{}; 1264 uint32_t address{};
1265 1265
1266 address = Convert<uint32_t>(GetReg32(system, 1)); 1266 address = Convert<uint32_t>(GetArg32(args, 1));
1267 1267
1268 ret = QueryPhysicalAddress64From32(system, std::addressof(out_info), address); 1268 ret = QueryPhysicalAddress64From32(system, std::addressof(out_info), address);
1269 1269
1270 SetReg32(system, 0, Convert<uint32_t>(ret)); 1270 SetArg32(args, 0, Convert<uint32_t>(ret));
1271 auto out_info_scatter = Convert<std::array<uint32_t, 4>>(out_info); 1271 auto out_info_scatter = Convert<std::array<uint32_t, 4>>(out_info);
1272 SetReg32(system, 1, out_info_scatter[0]); 1272 SetArg32(args, 1, out_info_scatter[0]);
1273 SetReg32(system, 2, out_info_scatter[1]); 1273 SetArg32(args, 2, out_info_scatter[1]);
1274 SetReg32(system, 3, out_info_scatter[2]); 1274 SetArg32(args, 3, out_info_scatter[2]);
1275 SetReg32(system, 4, out_info_scatter[3]); 1275 SetArg32(args, 4, out_info_scatter[3]);
1276} 1276}
1277 1277
1278static void SvcWrap_QueryIoMapping64From32(Core::System& system) { 1278static void SvcWrap_QueryIoMapping64From32(Core::System& system, std::span<uint64_t, 8> args) {
1279 Result ret{}; 1279 Result ret{};
1280 1280
1281 uint64_t out_address{}; 1281 uint64_t out_address{};
@@ -1284,19 +1284,19 @@ static void SvcWrap_QueryIoMapping64From32(Core::System& system) {
1284 uint32_t size{}; 1284 uint32_t size{};
1285 1285
1286 std::array<uint32_t, 2> physical_address_gather{}; 1286 std::array<uint32_t, 2> physical_address_gather{};
1287 physical_address_gather[0] = GetReg32(system, 2); 1287 physical_address_gather[0] = GetArg32(args, 2);
1288 physical_address_gather[1] = GetReg32(system, 3); 1288 physical_address_gather[1] = GetArg32(args, 3);
1289 physical_address = Convert<uint64_t>(physical_address_gather); 1289 physical_address = Convert<uint64_t>(physical_address_gather);
1290 size = Convert<uint32_t>(GetReg32(system, 0)); 1290 size = Convert<uint32_t>(GetArg32(args, 0));
1291 1291
1292 ret = QueryIoMapping64From32(system, std::addressof(out_address), std::addressof(out_size), physical_address, size); 1292 ret = QueryIoMapping64From32(system, std::addressof(out_address), std::addressof(out_size), physical_address, size);
1293 1293
1294 SetReg32(system, 0, Convert<uint32_t>(ret)); 1294 SetArg32(args, 0, Convert<uint32_t>(ret));
1295 SetReg32(system, 1, Convert<uint32_t>(out_address)); 1295 SetArg32(args, 1, Convert<uint32_t>(out_address));
1296 SetReg32(system, 2, Convert<uint32_t>(out_size)); 1296 SetArg32(args, 2, Convert<uint32_t>(out_size));
1297} 1297}
1298 1298
1299static void SvcWrap_CreateDeviceAddressSpace64From32(Core::System& system) { 1299static void SvcWrap_CreateDeviceAddressSpace64From32(Core::System& system, std::span<uint64_t, 8> args) {
1300 Result ret{}; 1300 Result ret{};
1301 1301
1302 Handle out_handle{}; 1302 Handle out_handle{};
@@ -1304,49 +1304,49 @@ static void SvcWrap_CreateDeviceAddressSpace64From32(Core::System& system) {
1304 uint64_t das_size{}; 1304 uint64_t das_size{};
1305 1305
1306 std::array<uint32_t, 2> das_address_gather{}; 1306 std::array<uint32_t, 2> das_address_gather{};
1307 das_address_gather[0] = GetReg32(system, 2); 1307 das_address_gather[0] = GetArg32(args, 2);
1308 das_address_gather[1] = GetReg32(system, 3); 1308 das_address_gather[1] = GetArg32(args, 3);
1309 das_address = Convert<uint64_t>(das_address_gather); 1309 das_address = Convert<uint64_t>(das_address_gather);
1310 std::array<uint32_t, 2> das_size_gather{}; 1310 std::array<uint32_t, 2> das_size_gather{};
1311 das_size_gather[0] = GetReg32(system, 0); 1311 das_size_gather[0] = GetArg32(args, 0);
1312 das_size_gather[1] = GetReg32(system, 1); 1312 das_size_gather[1] = GetArg32(args, 1);
1313 das_size = Convert<uint64_t>(das_size_gather); 1313 das_size = Convert<uint64_t>(das_size_gather);
1314 1314
1315 ret = CreateDeviceAddressSpace64From32(system, std::addressof(out_handle), das_address, das_size); 1315 ret = CreateDeviceAddressSpace64From32(system, std::addressof(out_handle), das_address, das_size);
1316 1316
1317 SetReg32(system, 0, Convert<uint32_t>(ret)); 1317 SetArg32(args, 0, Convert<uint32_t>(ret));
1318 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 1318 SetArg32(args, 1, Convert<uint32_t>(out_handle));
1319} 1319}
1320 1320
1321static void SvcWrap_AttachDeviceAddressSpace64From32(Core::System& system) { 1321static void SvcWrap_AttachDeviceAddressSpace64From32(Core::System& system, std::span<uint64_t, 8> args) {
1322 Result ret{}; 1322 Result ret{};
1323 1323
1324 DeviceName device_name{}; 1324 DeviceName device_name{};
1325 Handle das_handle{}; 1325 Handle das_handle{};
1326 1326
1327 device_name = Convert<DeviceName>(GetReg32(system, 0)); 1327 device_name = Convert<DeviceName>(GetArg32(args, 0));
1328 das_handle = Convert<Handle>(GetReg32(system, 1)); 1328 das_handle = Convert<Handle>(GetArg32(args, 1));
1329 1329
1330 ret = AttachDeviceAddressSpace64From32(system, device_name, das_handle); 1330 ret = AttachDeviceAddressSpace64From32(system, device_name, das_handle);
1331 1331
1332 SetReg32(system, 0, Convert<uint32_t>(ret)); 1332 SetArg32(args, 0, Convert<uint32_t>(ret));
1333} 1333}
1334 1334
1335static void SvcWrap_DetachDeviceAddressSpace64From32(Core::System& system) { 1335static void SvcWrap_DetachDeviceAddressSpace64From32(Core::System& system, std::span<uint64_t, 8> args) {
1336 Result ret{}; 1336 Result ret{};
1337 1337
1338 DeviceName device_name{}; 1338 DeviceName device_name{};
1339 Handle das_handle{}; 1339 Handle das_handle{};
1340 1340
1341 device_name = Convert<DeviceName>(GetReg32(system, 0)); 1341 device_name = Convert<DeviceName>(GetArg32(args, 0));
1342 das_handle = Convert<Handle>(GetReg32(system, 1)); 1342 das_handle = Convert<Handle>(GetArg32(args, 1));
1343 1343
1344 ret = DetachDeviceAddressSpace64From32(system, device_name, das_handle); 1344 ret = DetachDeviceAddressSpace64From32(system, device_name, das_handle);
1345 1345
1346 SetReg32(system, 0, Convert<uint32_t>(ret)); 1346 SetArg32(args, 0, Convert<uint32_t>(ret));
1347} 1347}
1348 1348
1349static void SvcWrap_MapDeviceAddressSpaceByForce64From32(Core::System& system) { 1349static void SvcWrap_MapDeviceAddressSpaceByForce64From32(Core::System& system, std::span<uint64_t, 8> args) {
1350 Result ret{}; 1350 Result ret{};
1351 1351
1352 Handle das_handle{}; 1352 Handle das_handle{};
@@ -1356,25 +1356,25 @@ static void SvcWrap_MapDeviceAddressSpaceByForce64From32(Core::System& system) {
1356 uint64_t device_address{}; 1356 uint64_t device_address{};
1357 uint32_t option{}; 1357 uint32_t option{};
1358 1358
1359 das_handle = Convert<Handle>(GetReg32(system, 0)); 1359 das_handle = Convert<Handle>(GetArg32(args, 0));
1360 process_handle = Convert<Handle>(GetReg32(system, 1)); 1360 process_handle = Convert<Handle>(GetArg32(args, 1));
1361 std::array<uint32_t, 2> process_address_gather{}; 1361 std::array<uint32_t, 2> process_address_gather{};
1362 process_address_gather[0] = GetReg32(system, 2); 1362 process_address_gather[0] = GetArg32(args, 2);
1363 process_address_gather[1] = GetReg32(system, 3); 1363 process_address_gather[1] = GetArg32(args, 3);
1364 process_address = Convert<uint64_t>(process_address_gather); 1364 process_address = Convert<uint64_t>(process_address_gather);
1365 size = Convert<uint32_t>(GetReg32(system, 4)); 1365 size = Convert<uint32_t>(GetArg32(args, 4));
1366 std::array<uint32_t, 2> device_address_gather{}; 1366 std::array<uint32_t, 2> device_address_gather{};
1367 device_address_gather[0] = GetReg32(system, 5); 1367 device_address_gather[0] = GetArg32(args, 5);
1368 device_address_gather[1] = GetReg32(system, 6); 1368 device_address_gather[1] = GetArg32(args, 6);
1369 device_address = Convert<uint64_t>(device_address_gather); 1369 device_address = Convert<uint64_t>(device_address_gather);
1370 option = Convert<uint32_t>(GetReg32(system, 7)); 1370 option = Convert<uint32_t>(GetArg32(args, 7));
1371 1371
1372 ret = MapDeviceAddressSpaceByForce64From32(system, das_handle, process_handle, process_address, size, device_address, option); 1372 ret = MapDeviceAddressSpaceByForce64From32(system, das_handle, process_handle, process_address, size, device_address, option);
1373 1373
1374 SetReg32(system, 0, Convert<uint32_t>(ret)); 1374 SetArg32(args, 0, Convert<uint32_t>(ret));
1375} 1375}
1376 1376
1377static void SvcWrap_MapDeviceAddressSpaceAligned64From32(Core::System& system) { 1377static void SvcWrap_MapDeviceAddressSpaceAligned64From32(Core::System& system, std::span<uint64_t, 8> args) {
1378 Result ret{}; 1378 Result ret{};
1379 1379
1380 Handle das_handle{}; 1380 Handle das_handle{};
@@ -1384,25 +1384,25 @@ static void SvcWrap_MapDeviceAddressSpaceAligned64From32(Core::System& system) {
1384 uint64_t device_address{}; 1384 uint64_t device_address{};
1385 uint32_t option{}; 1385 uint32_t option{};
1386 1386
1387 das_handle = Convert<Handle>(GetReg32(system, 0)); 1387 das_handle = Convert<Handle>(GetArg32(args, 0));
1388 process_handle = Convert<Handle>(GetReg32(system, 1)); 1388 process_handle = Convert<Handle>(GetArg32(args, 1));
1389 std::array<uint32_t, 2> process_address_gather{}; 1389 std::array<uint32_t, 2> process_address_gather{};
1390 process_address_gather[0] = GetReg32(system, 2); 1390 process_address_gather[0] = GetArg32(args, 2);
1391 process_address_gather[1] = GetReg32(system, 3); 1391 process_address_gather[1] = GetArg32(args, 3);
1392 process_address = Convert<uint64_t>(process_address_gather); 1392 process_address = Convert<uint64_t>(process_address_gather);
1393 size = Convert<uint32_t>(GetReg32(system, 4)); 1393 size = Convert<uint32_t>(GetArg32(args, 4));
1394 std::array<uint32_t, 2> device_address_gather{}; 1394 std::array<uint32_t, 2> device_address_gather{};
1395 device_address_gather[0] = GetReg32(system, 5); 1395 device_address_gather[0] = GetArg32(args, 5);
1396 device_address_gather[1] = GetReg32(system, 6); 1396 device_address_gather[1] = GetArg32(args, 6);
1397 device_address = Convert<uint64_t>(device_address_gather); 1397 device_address = Convert<uint64_t>(device_address_gather);
1398 option = Convert<uint32_t>(GetReg32(system, 7)); 1398 option = Convert<uint32_t>(GetArg32(args, 7));
1399 1399
1400 ret = MapDeviceAddressSpaceAligned64From32(system, das_handle, process_handle, process_address, size, device_address, option); 1400 ret = MapDeviceAddressSpaceAligned64From32(system, das_handle, process_handle, process_address, size, device_address, option);
1401 1401
1402 SetReg32(system, 0, Convert<uint32_t>(ret)); 1402 SetArg32(args, 0, Convert<uint32_t>(ret));
1403} 1403}
1404 1404
1405static void SvcWrap_UnmapDeviceAddressSpace64From32(Core::System& system) { 1405static void SvcWrap_UnmapDeviceAddressSpace64From32(Core::System& system, std::span<uint64_t, 8> args) {
1406 Result ret{}; 1406 Result ret{};
1407 1407
1408 Handle das_handle{}; 1408 Handle das_handle{};
@@ -1411,145 +1411,145 @@ static void SvcWrap_UnmapDeviceAddressSpace64From32(Core::System& system) {
1411 uint32_t size{}; 1411 uint32_t size{};
1412 uint64_t device_address{}; 1412 uint64_t device_address{};
1413 1413
1414 das_handle = Convert<Handle>(GetReg32(system, 0)); 1414 das_handle = Convert<Handle>(GetArg32(args, 0));
1415 process_handle = Convert<Handle>(GetReg32(system, 1)); 1415 process_handle = Convert<Handle>(GetArg32(args, 1));
1416 std::array<uint32_t, 2> process_address_gather{}; 1416 std::array<uint32_t, 2> process_address_gather{};
1417 process_address_gather[0] = GetReg32(system, 2); 1417 process_address_gather[0] = GetArg32(args, 2);
1418 process_address_gather[1] = GetReg32(system, 3); 1418 process_address_gather[1] = GetArg32(args, 3);
1419 process_address = Convert<uint64_t>(process_address_gather); 1419 process_address = Convert<uint64_t>(process_address_gather);
1420 size = Convert<uint32_t>(GetReg32(system, 4)); 1420 size = Convert<uint32_t>(GetArg32(args, 4));
1421 std::array<uint32_t, 2> device_address_gather{}; 1421 std::array<uint32_t, 2> device_address_gather{};
1422 device_address_gather[0] = GetReg32(system, 5); 1422 device_address_gather[0] = GetArg32(args, 5);
1423 device_address_gather[1] = GetReg32(system, 6); 1423 device_address_gather[1] = GetArg32(args, 6);
1424 device_address = Convert<uint64_t>(device_address_gather); 1424 device_address = Convert<uint64_t>(device_address_gather);
1425 1425
1426 ret = UnmapDeviceAddressSpace64From32(system, das_handle, process_handle, process_address, size, device_address); 1426 ret = UnmapDeviceAddressSpace64From32(system, das_handle, process_handle, process_address, size, device_address);
1427 1427
1428 SetReg32(system, 0, Convert<uint32_t>(ret)); 1428 SetArg32(args, 0, Convert<uint32_t>(ret));
1429} 1429}
1430 1430
1431static void SvcWrap_InvalidateProcessDataCache64From32(Core::System& system) { 1431static void SvcWrap_InvalidateProcessDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) {
1432 Result ret{}; 1432 Result ret{};
1433 1433
1434 Handle process_handle{}; 1434 Handle process_handle{};
1435 uint64_t address{}; 1435 uint64_t address{};
1436 uint64_t size{}; 1436 uint64_t size{};
1437 1437
1438 process_handle = Convert<Handle>(GetReg32(system, 0)); 1438 process_handle = Convert<Handle>(GetArg32(args, 0));
1439 std::array<uint32_t, 2> address_gather{}; 1439 std::array<uint32_t, 2> address_gather{};
1440 address_gather[0] = GetReg32(system, 2); 1440 address_gather[0] = GetArg32(args, 2);
1441 address_gather[1] = GetReg32(system, 3); 1441 address_gather[1] = GetArg32(args, 3);
1442 address = Convert<uint64_t>(address_gather); 1442 address = Convert<uint64_t>(address_gather);
1443 std::array<uint32_t, 2> size_gather{}; 1443 std::array<uint32_t, 2> size_gather{};
1444 size_gather[0] = GetReg32(system, 1); 1444 size_gather[0] = GetArg32(args, 1);
1445 size_gather[1] = GetReg32(system, 4); 1445 size_gather[1] = GetArg32(args, 4);
1446 size = Convert<uint64_t>(size_gather); 1446 size = Convert<uint64_t>(size_gather);
1447 1447
1448 ret = InvalidateProcessDataCache64From32(system, process_handle, address, size); 1448 ret = InvalidateProcessDataCache64From32(system, process_handle, address, size);
1449 1449
1450 SetReg32(system, 0, Convert<uint32_t>(ret)); 1450 SetArg32(args, 0, Convert<uint32_t>(ret));
1451} 1451}
1452 1452
1453static void SvcWrap_StoreProcessDataCache64From32(Core::System& system) { 1453static void SvcWrap_StoreProcessDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) {
1454 Result ret{}; 1454 Result ret{};
1455 1455
1456 Handle process_handle{}; 1456 Handle process_handle{};
1457 uint64_t address{}; 1457 uint64_t address{};
1458 uint64_t size{}; 1458 uint64_t size{};
1459 1459
1460 process_handle = Convert<Handle>(GetReg32(system, 0)); 1460 process_handle = Convert<Handle>(GetArg32(args, 0));
1461 std::array<uint32_t, 2> address_gather{}; 1461 std::array<uint32_t, 2> address_gather{};
1462 address_gather[0] = GetReg32(system, 2); 1462 address_gather[0] = GetArg32(args, 2);
1463 address_gather[1] = GetReg32(system, 3); 1463 address_gather[1] = GetArg32(args, 3);
1464 address = Convert<uint64_t>(address_gather); 1464 address = Convert<uint64_t>(address_gather);
1465 std::array<uint32_t, 2> size_gather{}; 1465 std::array<uint32_t, 2> size_gather{};
1466 size_gather[0] = GetReg32(system, 1); 1466 size_gather[0] = GetArg32(args, 1);
1467 size_gather[1] = GetReg32(system, 4); 1467 size_gather[1] = GetArg32(args, 4);
1468 size = Convert<uint64_t>(size_gather); 1468 size = Convert<uint64_t>(size_gather);
1469 1469
1470 ret = StoreProcessDataCache64From32(system, process_handle, address, size); 1470 ret = StoreProcessDataCache64From32(system, process_handle, address, size);
1471 1471
1472 SetReg32(system, 0, Convert<uint32_t>(ret)); 1472 SetArg32(args, 0, Convert<uint32_t>(ret));
1473} 1473}
1474 1474
1475static void SvcWrap_FlushProcessDataCache64From32(Core::System& system) { 1475static void SvcWrap_FlushProcessDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) {
1476 Result ret{}; 1476 Result ret{};
1477 1477
1478 Handle process_handle{}; 1478 Handle process_handle{};
1479 uint64_t address{}; 1479 uint64_t address{};
1480 uint64_t size{}; 1480 uint64_t size{};
1481 1481
1482 process_handle = Convert<Handle>(GetReg32(system, 0)); 1482 process_handle = Convert<Handle>(GetArg32(args, 0));
1483 std::array<uint32_t, 2> address_gather{}; 1483 std::array<uint32_t, 2> address_gather{};
1484 address_gather[0] = GetReg32(system, 2); 1484 address_gather[0] = GetArg32(args, 2);
1485 address_gather[1] = GetReg32(system, 3); 1485 address_gather[1] = GetArg32(args, 3);
1486 address = Convert<uint64_t>(address_gather); 1486 address = Convert<uint64_t>(address_gather);
1487 std::array<uint32_t, 2> size_gather{}; 1487 std::array<uint32_t, 2> size_gather{};
1488 size_gather[0] = GetReg32(system, 1); 1488 size_gather[0] = GetArg32(args, 1);
1489 size_gather[1] = GetReg32(system, 4); 1489 size_gather[1] = GetArg32(args, 4);
1490 size = Convert<uint64_t>(size_gather); 1490 size = Convert<uint64_t>(size_gather);
1491 1491
1492 ret = FlushProcessDataCache64From32(system, process_handle, address, size); 1492 ret = FlushProcessDataCache64From32(system, process_handle, address, size);
1493 1493
1494 SetReg32(system, 0, Convert<uint32_t>(ret)); 1494 SetArg32(args, 0, Convert<uint32_t>(ret));
1495} 1495}
1496 1496
1497static void SvcWrap_DebugActiveProcess64From32(Core::System& system) { 1497static void SvcWrap_DebugActiveProcess64From32(Core::System& system, std::span<uint64_t, 8> args) {
1498 Result ret{}; 1498 Result ret{};
1499 1499
1500 Handle out_handle{}; 1500 Handle out_handle{};
1501 uint64_t process_id{}; 1501 uint64_t process_id{};
1502 1502
1503 std::array<uint32_t, 2> process_id_gather{}; 1503 std::array<uint32_t, 2> process_id_gather{};
1504 process_id_gather[0] = GetReg32(system, 2); 1504 process_id_gather[0] = GetArg32(args, 2);
1505 process_id_gather[1] = GetReg32(system, 3); 1505 process_id_gather[1] = GetArg32(args, 3);
1506 process_id = Convert<uint64_t>(process_id_gather); 1506 process_id = Convert<uint64_t>(process_id_gather);
1507 1507
1508 ret = DebugActiveProcess64From32(system, std::addressof(out_handle), process_id); 1508 ret = DebugActiveProcess64From32(system, std::addressof(out_handle), process_id);
1509 1509
1510 SetReg32(system, 0, Convert<uint32_t>(ret)); 1510 SetArg32(args, 0, Convert<uint32_t>(ret));
1511 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 1511 SetArg32(args, 1, Convert<uint32_t>(out_handle));
1512} 1512}
1513 1513
1514static void SvcWrap_BreakDebugProcess64From32(Core::System& system) { 1514static void SvcWrap_BreakDebugProcess64From32(Core::System& system, std::span<uint64_t, 8> args) {
1515 Result ret{}; 1515 Result ret{};
1516 1516
1517 Handle debug_handle{}; 1517 Handle debug_handle{};
1518 1518
1519 debug_handle = Convert<Handle>(GetReg32(system, 0)); 1519 debug_handle = Convert<Handle>(GetArg32(args, 0));
1520 1520
1521 ret = BreakDebugProcess64From32(system, debug_handle); 1521 ret = BreakDebugProcess64From32(system, debug_handle);
1522 1522
1523 SetReg32(system, 0, Convert<uint32_t>(ret)); 1523 SetArg32(args, 0, Convert<uint32_t>(ret));
1524} 1524}
1525 1525
1526static void SvcWrap_TerminateDebugProcess64From32(Core::System& system) { 1526static void SvcWrap_TerminateDebugProcess64From32(Core::System& system, std::span<uint64_t, 8> args) {
1527 Result ret{}; 1527 Result ret{};
1528 1528
1529 Handle debug_handle{}; 1529 Handle debug_handle{};
1530 1530
1531 debug_handle = Convert<Handle>(GetReg32(system, 0)); 1531 debug_handle = Convert<Handle>(GetArg32(args, 0));
1532 1532
1533 ret = TerminateDebugProcess64From32(system, debug_handle); 1533 ret = TerminateDebugProcess64From32(system, debug_handle);
1534 1534
1535 SetReg32(system, 0, Convert<uint32_t>(ret)); 1535 SetArg32(args, 0, Convert<uint32_t>(ret));
1536} 1536}
1537 1537
1538static void SvcWrap_GetDebugEvent64From32(Core::System& system) { 1538static void SvcWrap_GetDebugEvent64From32(Core::System& system, std::span<uint64_t, 8> args) {
1539 Result ret{}; 1539 Result ret{};
1540 1540
1541 uint32_t out_info{}; 1541 uint32_t out_info{};
1542 Handle debug_handle{}; 1542 Handle debug_handle{};
1543 1543
1544 out_info = Convert<uint32_t>(GetReg32(system, 0)); 1544 out_info = Convert<uint32_t>(GetArg32(args, 0));
1545 debug_handle = Convert<Handle>(GetReg32(system, 1)); 1545 debug_handle = Convert<Handle>(GetArg32(args, 1));
1546 1546
1547 ret = GetDebugEvent64From32(system, out_info, debug_handle); 1547 ret = GetDebugEvent64From32(system, out_info, debug_handle);
1548 1548
1549 SetReg32(system, 0, Convert<uint32_t>(ret)); 1549 SetArg32(args, 0, Convert<uint32_t>(ret));
1550} 1550}
1551 1551
1552static void SvcWrap_ContinueDebugEvent64From32(Core::System& system) { 1552static void SvcWrap_ContinueDebugEvent64From32(Core::System& system, std::span<uint64_t, 8> args) {
1553 Result ret{}; 1553 Result ret{};
1554 1554
1555 Handle debug_handle{}; 1555 Handle debug_handle{};
@@ -1557,33 +1557,33 @@ static void SvcWrap_ContinueDebugEvent64From32(Core::System& system) {
1557 uint32_t thread_ids{}; 1557 uint32_t thread_ids{};
1558 int32_t num_thread_ids{}; 1558 int32_t num_thread_ids{};
1559 1559
1560 debug_handle = Convert<Handle>(GetReg32(system, 0)); 1560 debug_handle = Convert<Handle>(GetArg32(args, 0));
1561 flags = Convert<uint32_t>(GetReg32(system, 1)); 1561 flags = Convert<uint32_t>(GetArg32(args, 1));
1562 thread_ids = Convert<uint32_t>(GetReg32(system, 2)); 1562 thread_ids = Convert<uint32_t>(GetArg32(args, 2));
1563 num_thread_ids = Convert<int32_t>(GetReg32(system, 3)); 1563 num_thread_ids = Convert<int32_t>(GetArg32(args, 3));
1564 1564
1565 ret = ContinueDebugEvent64From32(system, debug_handle, flags, thread_ids, num_thread_ids); 1565 ret = ContinueDebugEvent64From32(system, debug_handle, flags, thread_ids, num_thread_ids);
1566 1566
1567 SetReg32(system, 0, Convert<uint32_t>(ret)); 1567 SetArg32(args, 0, Convert<uint32_t>(ret));
1568} 1568}
1569 1569
1570static void SvcWrap_GetProcessList64From32(Core::System& system) { 1570static void SvcWrap_GetProcessList64From32(Core::System& system, std::span<uint64_t, 8> args) {
1571 Result ret{}; 1571 Result ret{};
1572 1572
1573 int32_t out_num_processes{}; 1573 int32_t out_num_processes{};
1574 uint32_t out_process_ids{}; 1574 uint32_t out_process_ids{};
1575 int32_t max_out_count{}; 1575 int32_t max_out_count{};
1576 1576
1577 out_process_ids = Convert<uint32_t>(GetReg32(system, 1)); 1577 out_process_ids = Convert<uint32_t>(GetArg32(args, 1));
1578 max_out_count = Convert<int32_t>(GetReg32(system, 2)); 1578 max_out_count = Convert<int32_t>(GetArg32(args, 2));
1579 1579
1580 ret = GetProcessList64From32(system, std::addressof(out_num_processes), out_process_ids, max_out_count); 1580 ret = GetProcessList64From32(system, std::addressof(out_num_processes), out_process_ids, max_out_count);
1581 1581
1582 SetReg32(system, 0, Convert<uint32_t>(ret)); 1582 SetArg32(args, 0, Convert<uint32_t>(ret));
1583 SetReg32(system, 1, Convert<uint32_t>(out_num_processes)); 1583 SetArg32(args, 1, Convert<uint32_t>(out_num_processes));
1584} 1584}
1585 1585
1586static void SvcWrap_GetThreadList64From32(Core::System& system) { 1586static void SvcWrap_GetThreadList64From32(Core::System& system, std::span<uint64_t, 8> args) {
1587 Result ret{}; 1587 Result ret{};
1588 1588
1589 int32_t out_num_threads{}; 1589 int32_t out_num_threads{};
@@ -1591,17 +1591,17 @@ static void SvcWrap_GetThreadList64From32(Core::System& system) {
1591 int32_t max_out_count{}; 1591 int32_t max_out_count{};
1592 Handle debug_handle{}; 1592 Handle debug_handle{};
1593 1593
1594 out_thread_ids = Convert<uint32_t>(GetReg32(system, 1)); 1594 out_thread_ids = Convert<uint32_t>(GetArg32(args, 1));
1595 max_out_count = Convert<int32_t>(GetReg32(system, 2)); 1595 max_out_count = Convert<int32_t>(GetArg32(args, 2));
1596 debug_handle = Convert<Handle>(GetReg32(system, 3)); 1596 debug_handle = Convert<Handle>(GetArg32(args, 3));
1597 1597
1598 ret = GetThreadList64From32(system, std::addressof(out_num_threads), out_thread_ids, max_out_count, debug_handle); 1598 ret = GetThreadList64From32(system, std::addressof(out_num_threads), out_thread_ids, max_out_count, debug_handle);
1599 1599
1600 SetReg32(system, 0, Convert<uint32_t>(ret)); 1600 SetArg32(args, 0, Convert<uint32_t>(ret));
1601 SetReg32(system, 1, Convert<uint32_t>(out_num_threads)); 1601 SetArg32(args, 1, Convert<uint32_t>(out_num_threads));
1602} 1602}
1603 1603
1604static void SvcWrap_GetDebugThreadContext64From32(Core::System& system) { 1604static void SvcWrap_GetDebugThreadContext64From32(Core::System& system, std::span<uint64_t, 8> args) {
1605 Result ret{}; 1605 Result ret{};
1606 1606
1607 uint32_t out_context{}; 1607 uint32_t out_context{};
@@ -1609,20 +1609,20 @@ static void SvcWrap_GetDebugThreadContext64From32(Core::System& system) {
1609 uint64_t thread_id{}; 1609 uint64_t thread_id{};
1610 uint32_t context_flags{}; 1610 uint32_t context_flags{};
1611 1611
1612 out_context = Convert<uint32_t>(GetReg32(system, 0)); 1612 out_context = Convert<uint32_t>(GetArg32(args, 0));
1613 debug_handle = Convert<Handle>(GetReg32(system, 1)); 1613 debug_handle = Convert<Handle>(GetArg32(args, 1));
1614 std::array<uint32_t, 2> thread_id_gather{}; 1614 std::array<uint32_t, 2> thread_id_gather{};
1615 thread_id_gather[0] = GetReg32(system, 2); 1615 thread_id_gather[0] = GetArg32(args, 2);
1616 thread_id_gather[1] = GetReg32(system, 3); 1616 thread_id_gather[1] = GetArg32(args, 3);
1617 thread_id = Convert<uint64_t>(thread_id_gather); 1617 thread_id = Convert<uint64_t>(thread_id_gather);
1618 context_flags = Convert<uint32_t>(GetReg32(system, 4)); 1618 context_flags = Convert<uint32_t>(GetArg32(args, 4));
1619 1619
1620 ret = GetDebugThreadContext64From32(system, out_context, debug_handle, thread_id, context_flags); 1620 ret = GetDebugThreadContext64From32(system, out_context, debug_handle, thread_id, context_flags);
1621 1621
1622 SetReg32(system, 0, Convert<uint32_t>(ret)); 1622 SetArg32(args, 0, Convert<uint32_t>(ret));
1623} 1623}
1624 1624
1625static void SvcWrap_SetDebugThreadContext64From32(Core::System& system) { 1625static void SvcWrap_SetDebugThreadContext64From32(Core::System& system, std::span<uint64_t, 8> args) {
1626 Result ret{}; 1626 Result ret{};
1627 1627
1628 Handle debug_handle{}; 1628 Handle debug_handle{};
@@ -1630,20 +1630,20 @@ static void SvcWrap_SetDebugThreadContext64From32(Core::System& system) {
1630 uint32_t context{}; 1630 uint32_t context{};
1631 uint32_t context_flags{}; 1631 uint32_t context_flags{};
1632 1632
1633 debug_handle = Convert<Handle>(GetReg32(system, 0)); 1633 debug_handle = Convert<Handle>(GetArg32(args, 0));
1634 std::array<uint32_t, 2> thread_id_gather{}; 1634 std::array<uint32_t, 2> thread_id_gather{};
1635 thread_id_gather[0] = GetReg32(system, 2); 1635 thread_id_gather[0] = GetArg32(args, 2);
1636 thread_id_gather[1] = GetReg32(system, 3); 1636 thread_id_gather[1] = GetArg32(args, 3);
1637 thread_id = Convert<uint64_t>(thread_id_gather); 1637 thread_id = Convert<uint64_t>(thread_id_gather);
1638 context = Convert<uint32_t>(GetReg32(system, 1)); 1638 context = Convert<uint32_t>(GetArg32(args, 1));
1639 context_flags = Convert<uint32_t>(GetReg32(system, 4)); 1639 context_flags = Convert<uint32_t>(GetArg32(args, 4));
1640 1640
1641 ret = SetDebugThreadContext64From32(system, debug_handle, thread_id, context, context_flags); 1641 ret = SetDebugThreadContext64From32(system, debug_handle, thread_id, context, context_flags);
1642 1642
1643 SetReg32(system, 0, Convert<uint32_t>(ret)); 1643 SetArg32(args, 0, Convert<uint32_t>(ret));
1644} 1644}
1645 1645
1646static void SvcWrap_QueryDebugProcessMemory64From32(Core::System& system) { 1646static void SvcWrap_QueryDebugProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1647 Result ret{}; 1647 Result ret{};
1648 1648
1649 PageInfo out_page_info{}; 1649 PageInfo out_page_info{};
@@ -1651,17 +1651,17 @@ static void SvcWrap_QueryDebugProcessMemory64From32(Core::System& system) {
1651 Handle process_handle{}; 1651 Handle process_handle{};
1652 uint32_t address{}; 1652 uint32_t address{};
1653 1653
1654 out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); 1654 out_memory_info = Convert<uint32_t>(GetArg32(args, 0));
1655 process_handle = Convert<Handle>(GetReg32(system, 2)); 1655 process_handle = Convert<Handle>(GetArg32(args, 2));
1656 address = Convert<uint32_t>(GetReg32(system, 3)); 1656 address = Convert<uint32_t>(GetArg32(args, 3));
1657 1657
1658 ret = QueryDebugProcessMemory64From32(system, out_memory_info, std::addressof(out_page_info), process_handle, address); 1658 ret = QueryDebugProcessMemory64From32(system, out_memory_info, std::addressof(out_page_info), process_handle, address);
1659 1659
1660 SetReg32(system, 0, Convert<uint32_t>(ret)); 1660 SetArg32(args, 0, Convert<uint32_t>(ret));
1661 SetReg32(system, 1, Convert<uint32_t>(out_page_info)); 1661 SetArg32(args, 1, Convert<uint32_t>(out_page_info));
1662} 1662}
1663 1663
1664static void SvcWrap_ReadDebugProcessMemory64From32(Core::System& system) { 1664static void SvcWrap_ReadDebugProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1665 Result ret{}; 1665 Result ret{};
1666 1666
1667 uint32_t buffer{}; 1667 uint32_t buffer{};
@@ -1669,17 +1669,17 @@ static void SvcWrap_ReadDebugProcessMemory64From32(Core::System& system) {
1669 uint32_t address{}; 1669 uint32_t address{};
1670 uint32_t size{}; 1670 uint32_t size{};
1671 1671
1672 buffer = Convert<uint32_t>(GetReg32(system, 0)); 1672 buffer = Convert<uint32_t>(GetArg32(args, 0));
1673 debug_handle = Convert<Handle>(GetReg32(system, 1)); 1673 debug_handle = Convert<Handle>(GetArg32(args, 1));
1674 address = Convert<uint32_t>(GetReg32(system, 2)); 1674 address = Convert<uint32_t>(GetArg32(args, 2));
1675 size = Convert<uint32_t>(GetReg32(system, 3)); 1675 size = Convert<uint32_t>(GetArg32(args, 3));
1676 1676
1677 ret = ReadDebugProcessMemory64From32(system, buffer, debug_handle, address, size); 1677 ret = ReadDebugProcessMemory64From32(system, buffer, debug_handle, address, size);
1678 1678
1679 SetReg32(system, 0, Convert<uint32_t>(ret)); 1679 SetArg32(args, 0, Convert<uint32_t>(ret));
1680} 1680}
1681 1681
1682static void SvcWrap_WriteDebugProcessMemory64From32(Core::System& system) { 1682static void SvcWrap_WriteDebugProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1683 Result ret{}; 1683 Result ret{};
1684 1684
1685 Handle debug_handle{}; 1685 Handle debug_handle{};
@@ -1687,39 +1687,39 @@ static void SvcWrap_WriteDebugProcessMemory64From32(Core::System& system) {
1687 uint32_t address{}; 1687 uint32_t address{};
1688 uint32_t size{}; 1688 uint32_t size{};
1689 1689
1690 debug_handle = Convert<Handle>(GetReg32(system, 0)); 1690 debug_handle = Convert<Handle>(GetArg32(args, 0));
1691 buffer = Convert<uint32_t>(GetReg32(system, 1)); 1691 buffer = Convert<uint32_t>(GetArg32(args, 1));
1692 address = Convert<uint32_t>(GetReg32(system, 2)); 1692 address = Convert<uint32_t>(GetArg32(args, 2));
1693 size = Convert<uint32_t>(GetReg32(system, 3)); 1693 size = Convert<uint32_t>(GetArg32(args, 3));
1694 1694
1695 ret = WriteDebugProcessMemory64From32(system, debug_handle, buffer, address, size); 1695 ret = WriteDebugProcessMemory64From32(system, debug_handle, buffer, address, size);
1696 1696
1697 SetReg32(system, 0, Convert<uint32_t>(ret)); 1697 SetArg32(args, 0, Convert<uint32_t>(ret));
1698} 1698}
1699 1699
1700static void SvcWrap_SetHardwareBreakPoint64From32(Core::System& system) { 1700static void SvcWrap_SetHardwareBreakPoint64From32(Core::System& system, std::span<uint64_t, 8> args) {
1701 Result ret{}; 1701 Result ret{};
1702 1702
1703 HardwareBreakPointRegisterName name{}; 1703 HardwareBreakPointRegisterName name{};
1704 uint64_t flags{}; 1704 uint64_t flags{};
1705 uint64_t value{}; 1705 uint64_t value{};
1706 1706
1707 name = Convert<HardwareBreakPointRegisterName>(GetReg32(system, 0)); 1707 name = Convert<HardwareBreakPointRegisterName>(GetArg32(args, 0));
1708 std::array<uint32_t, 2> flags_gather{}; 1708 std::array<uint32_t, 2> flags_gather{};
1709 flags_gather[0] = GetReg32(system, 2); 1709 flags_gather[0] = GetArg32(args, 2);
1710 flags_gather[1] = GetReg32(system, 3); 1710 flags_gather[1] = GetArg32(args, 3);
1711 flags = Convert<uint64_t>(flags_gather); 1711 flags = Convert<uint64_t>(flags_gather);
1712 std::array<uint32_t, 2> value_gather{}; 1712 std::array<uint32_t, 2> value_gather{};
1713 value_gather[0] = GetReg32(system, 1); 1713 value_gather[0] = GetArg32(args, 1);
1714 value_gather[1] = GetReg32(system, 4); 1714 value_gather[1] = GetArg32(args, 4);
1715 value = Convert<uint64_t>(value_gather); 1715 value = Convert<uint64_t>(value_gather);
1716 1716
1717 ret = SetHardwareBreakPoint64From32(system, name, flags, value); 1717 ret = SetHardwareBreakPoint64From32(system, name, flags, value);
1718 1718
1719 SetReg32(system, 0, Convert<uint32_t>(ret)); 1719 SetArg32(args, 0, Convert<uint32_t>(ret));
1720} 1720}
1721 1721
1722static void SvcWrap_GetDebugThreadParam64From32(Core::System& system) { 1722static void SvcWrap_GetDebugThreadParam64From32(Core::System& system, std::span<uint64_t, 8> args) {
1723 Result ret{}; 1723 Result ret{};
1724 1724
1725 uint64_t out_64{}; 1725 uint64_t out_64{};
@@ -1728,23 +1728,23 @@ static void SvcWrap_GetDebugThreadParam64From32(Core::System& system) {
1728 uint64_t thread_id{}; 1728 uint64_t thread_id{};
1729 DebugThreadParam param{}; 1729 DebugThreadParam param{};
1730 1730
1731 debug_handle = Convert<Handle>(GetReg32(system, 2)); 1731 debug_handle = Convert<Handle>(GetArg32(args, 2));
1732 std::array<uint32_t, 2> thread_id_gather{}; 1732 std::array<uint32_t, 2> thread_id_gather{};
1733 thread_id_gather[0] = GetReg32(system, 0); 1733 thread_id_gather[0] = GetArg32(args, 0);
1734 thread_id_gather[1] = GetReg32(system, 1); 1734 thread_id_gather[1] = GetArg32(args, 1);
1735 thread_id = Convert<uint64_t>(thread_id_gather); 1735 thread_id = Convert<uint64_t>(thread_id_gather);
1736 param = Convert<DebugThreadParam>(GetReg32(system, 3)); 1736 param = Convert<DebugThreadParam>(GetArg32(args, 3));
1737 1737
1738 ret = GetDebugThreadParam64From32(system, std::addressof(out_64), std::addressof(out_32), debug_handle, thread_id, param); 1738 ret = GetDebugThreadParam64From32(system, std::addressof(out_64), std::addressof(out_32), debug_handle, thread_id, param);
1739 1739
1740 SetReg32(system, 0, Convert<uint32_t>(ret)); 1740 SetArg32(args, 0, Convert<uint32_t>(ret));
1741 auto out_64_scatter = Convert<std::array<uint32_t, 2>>(out_64); 1741 auto out_64_scatter = Convert<std::array<uint32_t, 2>>(out_64);
1742 SetReg32(system, 1, out_64_scatter[0]); 1742 SetArg32(args, 1, out_64_scatter[0]);
1743 SetReg32(system, 2, out_64_scatter[1]); 1743 SetArg32(args, 2, out_64_scatter[1]);
1744 SetReg32(system, 3, Convert<uint32_t>(out_32)); 1744 SetArg32(args, 3, Convert<uint32_t>(out_32));
1745} 1745}
1746 1746
1747static void SvcWrap_GetSystemInfo64From32(Core::System& system) { 1747static void SvcWrap_GetSystemInfo64From32(Core::System& system, std::span<uint64_t, 8> args) {
1748 Result ret{}; 1748 Result ret{};
1749 1749
1750 uint64_t out{}; 1750 uint64_t out{};
@@ -1752,22 +1752,22 @@ static void SvcWrap_GetSystemInfo64From32(Core::System& system) {
1752 Handle handle{}; 1752 Handle handle{};
1753 uint64_t info_subtype{}; 1753 uint64_t info_subtype{};
1754 1754
1755 info_type = Convert<SystemInfoType>(GetReg32(system, 1)); 1755 info_type = Convert<SystemInfoType>(GetArg32(args, 1));
1756 handle = Convert<Handle>(GetReg32(system, 2)); 1756 handle = Convert<Handle>(GetArg32(args, 2));
1757 std::array<uint32_t, 2> info_subtype_gather{}; 1757 std::array<uint32_t, 2> info_subtype_gather{};
1758 info_subtype_gather[0] = GetReg32(system, 0); 1758 info_subtype_gather[0] = GetArg32(args, 0);
1759 info_subtype_gather[1] = GetReg32(system, 3); 1759 info_subtype_gather[1] = GetArg32(args, 3);
1760 info_subtype = Convert<uint64_t>(info_subtype_gather); 1760 info_subtype = Convert<uint64_t>(info_subtype_gather);
1761 1761
1762 ret = GetSystemInfo64From32(system, std::addressof(out), info_type, handle, info_subtype); 1762 ret = GetSystemInfo64From32(system, std::addressof(out), info_type, handle, info_subtype);
1763 1763
1764 SetReg32(system, 0, Convert<uint32_t>(ret)); 1764 SetArg32(args, 0, Convert<uint32_t>(ret));
1765 auto out_scatter = Convert<std::array<uint32_t, 2>>(out); 1765 auto out_scatter = Convert<std::array<uint32_t, 2>>(out);
1766 SetReg32(system, 1, out_scatter[0]); 1766 SetArg32(args, 1, out_scatter[0]);
1767 SetReg32(system, 2, out_scatter[1]); 1767 SetArg32(args, 2, out_scatter[1]);
1768} 1768}
1769 1769
1770static void SvcWrap_CreatePort64From32(Core::System& system) { 1770static void SvcWrap_CreatePort64From32(Core::System& system, std::span<uint64_t, 8> args) {
1771 Result ret{}; 1771 Result ret{};
1772 1772
1773 Handle out_server_handle{}; 1773 Handle out_server_handle{};
@@ -1776,48 +1776,48 @@ static void SvcWrap_CreatePort64From32(Core::System& system) {
1776 bool is_light{}; 1776 bool is_light{};
1777 uint32_t name{}; 1777 uint32_t name{};
1778 1778
1779 max_sessions = Convert<int32_t>(GetReg32(system, 2)); 1779 max_sessions = Convert<int32_t>(GetArg32(args, 2));
1780 is_light = Convert<bool>(GetReg32(system, 3)); 1780 is_light = Convert<bool>(GetArg32(args, 3));
1781 name = Convert<uint32_t>(GetReg32(system, 0)); 1781 name = Convert<uint32_t>(GetArg32(args, 0));
1782 1782
1783 ret = CreatePort64From32(system, std::addressof(out_server_handle), std::addressof(out_client_handle), max_sessions, is_light, name); 1783 ret = CreatePort64From32(system, std::addressof(out_server_handle), std::addressof(out_client_handle), max_sessions, is_light, name);
1784 1784
1785 SetReg32(system, 0, Convert<uint32_t>(ret)); 1785 SetArg32(args, 0, Convert<uint32_t>(ret));
1786 SetReg32(system, 1, Convert<uint32_t>(out_server_handle)); 1786 SetArg32(args, 1, Convert<uint32_t>(out_server_handle));
1787 SetReg32(system, 2, Convert<uint32_t>(out_client_handle)); 1787 SetArg32(args, 2, Convert<uint32_t>(out_client_handle));
1788} 1788}
1789 1789
1790static void SvcWrap_ManageNamedPort64From32(Core::System& system) { 1790static void SvcWrap_ManageNamedPort64From32(Core::System& system, std::span<uint64_t, 8> args) {
1791 Result ret{}; 1791 Result ret{};
1792 1792
1793 Handle out_server_handle{}; 1793 Handle out_server_handle{};
1794 uint32_t name{}; 1794 uint32_t name{};
1795 int32_t max_sessions{}; 1795 int32_t max_sessions{};
1796 1796
1797 name = Convert<uint32_t>(GetReg32(system, 1)); 1797 name = Convert<uint32_t>(GetArg32(args, 1));
1798 max_sessions = Convert<int32_t>(GetReg32(system, 2)); 1798 max_sessions = Convert<int32_t>(GetArg32(args, 2));
1799 1799
1800 ret = ManageNamedPort64From32(system, std::addressof(out_server_handle), name, max_sessions); 1800 ret = ManageNamedPort64From32(system, std::addressof(out_server_handle), name, max_sessions);
1801 1801
1802 SetReg32(system, 0, Convert<uint32_t>(ret)); 1802 SetArg32(args, 0, Convert<uint32_t>(ret));
1803 SetReg32(system, 1, Convert<uint32_t>(out_server_handle)); 1803 SetArg32(args, 1, Convert<uint32_t>(out_server_handle));
1804} 1804}
1805 1805
1806static void SvcWrap_ConnectToPort64From32(Core::System& system) { 1806static void SvcWrap_ConnectToPort64From32(Core::System& system, std::span<uint64_t, 8> args) {
1807 Result ret{}; 1807 Result ret{};
1808 1808
1809 Handle out_handle{}; 1809 Handle out_handle{};
1810 Handle port{}; 1810 Handle port{};
1811 1811
1812 port = Convert<Handle>(GetReg32(system, 1)); 1812 port = Convert<Handle>(GetArg32(args, 1));
1813 1813
1814 ret = ConnectToPort64From32(system, std::addressof(out_handle), port); 1814 ret = ConnectToPort64From32(system, std::addressof(out_handle), port);
1815 1815
1816 SetReg32(system, 0, Convert<uint32_t>(ret)); 1816 SetArg32(args, 0, Convert<uint32_t>(ret));
1817 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 1817 SetArg32(args, 1, Convert<uint32_t>(out_handle));
1818} 1818}
1819 1819
1820static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system) { 1820static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system, std::span<uint64_t, 8> args) {
1821 Result ret{}; 1821 Result ret{};
1822 1822
1823 Handle process_handle{}; 1823 Handle process_handle{};
@@ -1825,23 +1825,23 @@ static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system) {
1825 uint64_t size{}; 1825 uint64_t size{};
1826 MemoryPermission perm{}; 1826 MemoryPermission perm{};
1827 1827
1828 process_handle = Convert<Handle>(GetReg32(system, 0)); 1828 process_handle = Convert<Handle>(GetArg32(args, 0));
1829 std::array<uint32_t, 2> address_gather{}; 1829 std::array<uint32_t, 2> address_gather{};
1830 address_gather[0] = GetReg32(system, 2); 1830 address_gather[0] = GetArg32(args, 2);
1831 address_gather[1] = GetReg32(system, 3); 1831 address_gather[1] = GetArg32(args, 3);
1832 address = Convert<uint64_t>(address_gather); 1832 address = Convert<uint64_t>(address_gather);
1833 std::array<uint32_t, 2> size_gather{}; 1833 std::array<uint32_t, 2> size_gather{};
1834 size_gather[0] = GetReg32(system, 1); 1834 size_gather[0] = GetArg32(args, 1);
1835 size_gather[1] = GetReg32(system, 4); 1835 size_gather[1] = GetArg32(args, 4);
1836 size = Convert<uint64_t>(size_gather); 1836 size = Convert<uint64_t>(size_gather);
1837 perm = Convert<MemoryPermission>(GetReg32(system, 5)); 1837 perm = Convert<MemoryPermission>(GetArg32(args, 5));
1838 1838
1839 ret = SetProcessMemoryPermission64From32(system, process_handle, address, size, perm); 1839 ret = SetProcessMemoryPermission64From32(system, process_handle, address, size, perm);
1840 1840
1841 SetReg32(system, 0, Convert<uint32_t>(ret)); 1841 SetArg32(args, 0, Convert<uint32_t>(ret));
1842} 1842}
1843 1843
1844static void SvcWrap_MapProcessMemory64From32(Core::System& system) { 1844static void SvcWrap_MapProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1845 Result ret{}; 1845 Result ret{};
1846 1846
1847 uint32_t dst_address{}; 1847 uint32_t dst_address{};
@@ -1849,20 +1849,20 @@ static void SvcWrap_MapProcessMemory64From32(Core::System& system) {
1849 uint64_t src_address{}; 1849 uint64_t src_address{};
1850 uint32_t size{}; 1850 uint32_t size{};
1851 1851
1852 dst_address = Convert<uint32_t>(GetReg32(system, 0)); 1852 dst_address = Convert<uint32_t>(GetArg32(args, 0));
1853 process_handle = Convert<Handle>(GetReg32(system, 1)); 1853 process_handle = Convert<Handle>(GetArg32(args, 1));
1854 std::array<uint32_t, 2> src_address_gather{}; 1854 std::array<uint32_t, 2> src_address_gather{};
1855 src_address_gather[0] = GetReg32(system, 2); 1855 src_address_gather[0] = GetArg32(args, 2);
1856 src_address_gather[1] = GetReg32(system, 3); 1856 src_address_gather[1] = GetArg32(args, 3);
1857 src_address = Convert<uint64_t>(src_address_gather); 1857 src_address = Convert<uint64_t>(src_address_gather);
1858 size = Convert<uint32_t>(GetReg32(system, 4)); 1858 size = Convert<uint32_t>(GetArg32(args, 4));
1859 1859
1860 ret = MapProcessMemory64From32(system, dst_address, process_handle, src_address, size); 1860 ret = MapProcessMemory64From32(system, dst_address, process_handle, src_address, size);
1861 1861
1862 SetReg32(system, 0, Convert<uint32_t>(ret)); 1862 SetArg32(args, 0, Convert<uint32_t>(ret));
1863} 1863}
1864 1864
1865static void SvcWrap_UnmapProcessMemory64From32(Core::System& system) { 1865static void SvcWrap_UnmapProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1866 Result ret{}; 1866 Result ret{};
1867 1867
1868 uint32_t dst_address{}; 1868 uint32_t dst_address{};
@@ -1870,20 +1870,20 @@ static void SvcWrap_UnmapProcessMemory64From32(Core::System& system) {
1870 uint64_t src_address{}; 1870 uint64_t src_address{};
1871 uint32_t size{}; 1871 uint32_t size{};
1872 1872
1873 dst_address = Convert<uint32_t>(GetReg32(system, 0)); 1873 dst_address = Convert<uint32_t>(GetArg32(args, 0));
1874 process_handle = Convert<Handle>(GetReg32(system, 1)); 1874 process_handle = Convert<Handle>(GetArg32(args, 1));
1875 std::array<uint32_t, 2> src_address_gather{}; 1875 std::array<uint32_t, 2> src_address_gather{};
1876 src_address_gather[0] = GetReg32(system, 2); 1876 src_address_gather[0] = GetArg32(args, 2);
1877 src_address_gather[1] = GetReg32(system, 3); 1877 src_address_gather[1] = GetArg32(args, 3);
1878 src_address = Convert<uint64_t>(src_address_gather); 1878 src_address = Convert<uint64_t>(src_address_gather);
1879 size = Convert<uint32_t>(GetReg32(system, 4)); 1879 size = Convert<uint32_t>(GetArg32(args, 4));
1880 1880
1881 ret = UnmapProcessMemory64From32(system, dst_address, process_handle, src_address, size); 1881 ret = UnmapProcessMemory64From32(system, dst_address, process_handle, src_address, size);
1882 1882
1883 SetReg32(system, 0, Convert<uint32_t>(ret)); 1883 SetArg32(args, 0, Convert<uint32_t>(ret));
1884} 1884}
1885 1885
1886static void SvcWrap_QueryProcessMemory64From32(Core::System& system) { 1886static void SvcWrap_QueryProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1887 Result ret{}; 1887 Result ret{};
1888 1888
1889 PageInfo out_page_info{}; 1889 PageInfo out_page_info{};
@@ -1891,20 +1891,20 @@ static void SvcWrap_QueryProcessMemory64From32(Core::System& system) {
1891 Handle process_handle{}; 1891 Handle process_handle{};
1892 uint64_t address{}; 1892 uint64_t address{};
1893 1893
1894 out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); 1894 out_memory_info = Convert<uint32_t>(GetArg32(args, 0));
1895 process_handle = Convert<Handle>(GetReg32(system, 2)); 1895 process_handle = Convert<Handle>(GetArg32(args, 2));
1896 std::array<uint32_t, 2> address_gather{}; 1896 std::array<uint32_t, 2> address_gather{};
1897 address_gather[0] = GetReg32(system, 1); 1897 address_gather[0] = GetArg32(args, 1);
1898 address_gather[1] = GetReg32(system, 3); 1898 address_gather[1] = GetArg32(args, 3);
1899 address = Convert<uint64_t>(address_gather); 1899 address = Convert<uint64_t>(address_gather);
1900 1900
1901 ret = QueryProcessMemory64From32(system, out_memory_info, std::addressof(out_page_info), process_handle, address); 1901 ret = QueryProcessMemory64From32(system, out_memory_info, std::addressof(out_page_info), process_handle, address);
1902 1902
1903 SetReg32(system, 0, Convert<uint32_t>(ret)); 1903 SetArg32(args, 0, Convert<uint32_t>(ret));
1904 SetReg32(system, 1, Convert<uint32_t>(out_page_info)); 1904 SetArg32(args, 1, Convert<uint32_t>(out_page_info));
1905} 1905}
1906 1906
1907static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system) { 1907static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1908 Result ret{}; 1908 Result ret{};
1909 1909
1910 Handle process_handle{}; 1910 Handle process_handle{};
@@ -1912,26 +1912,26 @@ static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system) {
1912 uint64_t src_address{}; 1912 uint64_t src_address{};
1913 uint64_t size{}; 1913 uint64_t size{};
1914 1914
1915 process_handle = Convert<Handle>(GetReg32(system, 0)); 1915 process_handle = Convert<Handle>(GetArg32(args, 0));
1916 std::array<uint32_t, 2> dst_address_gather{}; 1916 std::array<uint32_t, 2> dst_address_gather{};
1917 dst_address_gather[0] = GetReg32(system, 2); 1917 dst_address_gather[0] = GetArg32(args, 2);
1918 dst_address_gather[1] = GetReg32(system, 3); 1918 dst_address_gather[1] = GetArg32(args, 3);
1919 dst_address = Convert<uint64_t>(dst_address_gather); 1919 dst_address = Convert<uint64_t>(dst_address_gather);
1920 std::array<uint32_t, 2> src_address_gather{}; 1920 std::array<uint32_t, 2> src_address_gather{};
1921 src_address_gather[0] = GetReg32(system, 1); 1921 src_address_gather[0] = GetArg32(args, 1);
1922 src_address_gather[1] = GetReg32(system, 4); 1922 src_address_gather[1] = GetArg32(args, 4);
1923 src_address = Convert<uint64_t>(src_address_gather); 1923 src_address = Convert<uint64_t>(src_address_gather);
1924 std::array<uint32_t, 2> size_gather{}; 1924 std::array<uint32_t, 2> size_gather{};
1925 size_gather[0] = GetReg32(system, 5); 1925 size_gather[0] = GetArg32(args, 5);
1926 size_gather[1] = GetReg32(system, 6); 1926 size_gather[1] = GetArg32(args, 6);
1927 size = Convert<uint64_t>(size_gather); 1927 size = Convert<uint64_t>(size_gather);
1928 1928
1929 ret = MapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size); 1929 ret = MapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size);
1930 1930
1931 SetReg32(system, 0, Convert<uint32_t>(ret)); 1931 SetArg32(args, 0, Convert<uint32_t>(ret));
1932} 1932}
1933 1933
1934static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system) { 1934static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
1935 Result ret{}; 1935 Result ret{};
1936 1936
1937 Handle process_handle{}; 1937 Handle process_handle{};
@@ -1939,26 +1939,26 @@ static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system) {
1939 uint64_t src_address{}; 1939 uint64_t src_address{};
1940 uint64_t size{}; 1940 uint64_t size{};
1941 1941
1942 process_handle = Convert<Handle>(GetReg32(system, 0)); 1942 process_handle = Convert<Handle>(GetArg32(args, 0));
1943 std::array<uint32_t, 2> dst_address_gather{}; 1943 std::array<uint32_t, 2> dst_address_gather{};
1944 dst_address_gather[0] = GetReg32(system, 2); 1944 dst_address_gather[0] = GetArg32(args, 2);
1945 dst_address_gather[1] = GetReg32(system, 3); 1945 dst_address_gather[1] = GetArg32(args, 3);
1946 dst_address = Convert<uint64_t>(dst_address_gather); 1946 dst_address = Convert<uint64_t>(dst_address_gather);
1947 std::array<uint32_t, 2> src_address_gather{}; 1947 std::array<uint32_t, 2> src_address_gather{};
1948 src_address_gather[0] = GetReg32(system, 1); 1948 src_address_gather[0] = GetArg32(args, 1);
1949 src_address_gather[1] = GetReg32(system, 4); 1949 src_address_gather[1] = GetArg32(args, 4);
1950 src_address = Convert<uint64_t>(src_address_gather); 1950 src_address = Convert<uint64_t>(src_address_gather);
1951 std::array<uint32_t, 2> size_gather{}; 1951 std::array<uint32_t, 2> size_gather{};
1952 size_gather[0] = GetReg32(system, 5); 1952 size_gather[0] = GetArg32(args, 5);
1953 size_gather[1] = GetReg32(system, 6); 1953 size_gather[1] = GetArg32(args, 6);
1954 size = Convert<uint64_t>(size_gather); 1954 size = Convert<uint64_t>(size_gather);
1955 1955
1956 ret = UnmapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size); 1956 ret = UnmapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size);
1957 1957
1958 SetReg32(system, 0, Convert<uint32_t>(ret)); 1958 SetArg32(args, 0, Convert<uint32_t>(ret));
1959} 1959}
1960 1960
1961static void SvcWrap_CreateProcess64From32(Core::System& system) { 1961static void SvcWrap_CreateProcess64From32(Core::System& system, std::span<uint64_t, 8> args) {
1962 Result ret{}; 1962 Result ret{};
1963 1963
1964 Handle out_handle{}; 1964 Handle out_handle{};
@@ -1966,17 +1966,17 @@ static void SvcWrap_CreateProcess64From32(Core::System& system) {
1966 uint32_t caps{}; 1966 uint32_t caps{};
1967 int32_t num_caps{}; 1967 int32_t num_caps{};
1968 1968
1969 parameters = Convert<uint32_t>(GetReg32(system, 1)); 1969 parameters = Convert<uint32_t>(GetArg32(args, 1));
1970 caps = Convert<uint32_t>(GetReg32(system, 2)); 1970 caps = Convert<uint32_t>(GetArg32(args, 2));
1971 num_caps = Convert<int32_t>(GetReg32(system, 3)); 1971 num_caps = Convert<int32_t>(GetArg32(args, 3));
1972 1972
1973 ret = CreateProcess64From32(system, std::addressof(out_handle), parameters, caps, num_caps); 1973 ret = CreateProcess64From32(system, std::addressof(out_handle), parameters, caps, num_caps);
1974 1974
1975 SetReg32(system, 0, Convert<uint32_t>(ret)); 1975 SetArg32(args, 0, Convert<uint32_t>(ret));
1976 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 1976 SetArg32(args, 1, Convert<uint32_t>(out_handle));
1977} 1977}
1978 1978
1979static void SvcWrap_StartProcess64From32(Core::System& system) { 1979static void SvcWrap_StartProcess64From32(Core::System& system, std::span<uint64_t, 8> args) {
1980 Result ret{}; 1980 Result ret{};
1981 1981
1982 Handle process_handle{}; 1982 Handle process_handle{};
@@ -1984,138 +1984,138 @@ static void SvcWrap_StartProcess64From32(Core::System& system) {
1984 int32_t core_id{}; 1984 int32_t core_id{};
1985 uint64_t main_thread_stack_size{}; 1985 uint64_t main_thread_stack_size{};
1986 1986
1987 process_handle = Convert<Handle>(GetReg32(system, 0)); 1987 process_handle = Convert<Handle>(GetArg32(args, 0));
1988 priority = Convert<int32_t>(GetReg32(system, 1)); 1988 priority = Convert<int32_t>(GetArg32(args, 1));
1989 core_id = Convert<int32_t>(GetReg32(system, 2)); 1989 core_id = Convert<int32_t>(GetArg32(args, 2));
1990 std::array<uint32_t, 2> main_thread_stack_size_gather{}; 1990 std::array<uint32_t, 2> main_thread_stack_size_gather{};
1991 main_thread_stack_size_gather[0] = GetReg32(system, 3); 1991 main_thread_stack_size_gather[0] = GetArg32(args, 3);
1992 main_thread_stack_size_gather[1] = GetReg32(system, 4); 1992 main_thread_stack_size_gather[1] = GetArg32(args, 4);
1993 main_thread_stack_size = Convert<uint64_t>(main_thread_stack_size_gather); 1993 main_thread_stack_size = Convert<uint64_t>(main_thread_stack_size_gather);
1994 1994
1995 ret = StartProcess64From32(system, process_handle, priority, core_id, main_thread_stack_size); 1995 ret = StartProcess64From32(system, process_handle, priority, core_id, main_thread_stack_size);
1996 1996
1997 SetReg32(system, 0, Convert<uint32_t>(ret)); 1997 SetArg32(args, 0, Convert<uint32_t>(ret));
1998} 1998}
1999 1999
2000static void SvcWrap_TerminateProcess64From32(Core::System& system) { 2000static void SvcWrap_TerminateProcess64From32(Core::System& system, std::span<uint64_t, 8> args) {
2001 Result ret{}; 2001 Result ret{};
2002 2002
2003 Handle process_handle{}; 2003 Handle process_handle{};
2004 2004
2005 process_handle = Convert<Handle>(GetReg32(system, 0)); 2005 process_handle = Convert<Handle>(GetArg32(args, 0));
2006 2006
2007 ret = TerminateProcess64From32(system, process_handle); 2007 ret = TerminateProcess64From32(system, process_handle);
2008 2008
2009 SetReg32(system, 0, Convert<uint32_t>(ret)); 2009 SetArg32(args, 0, Convert<uint32_t>(ret));
2010} 2010}
2011 2011
2012static void SvcWrap_GetProcessInfo64From32(Core::System& system) { 2012static void SvcWrap_GetProcessInfo64From32(Core::System& system, std::span<uint64_t, 8> args) {
2013 Result ret{}; 2013 Result ret{};
2014 2014
2015 int64_t out_info{}; 2015 int64_t out_info{};
2016 Handle process_handle{}; 2016 Handle process_handle{};
2017 ProcessInfoType info_type{}; 2017 ProcessInfoType info_type{};
2018 2018
2019 process_handle = Convert<Handle>(GetReg32(system, 1)); 2019 process_handle = Convert<Handle>(GetArg32(args, 1));
2020 info_type = Convert<ProcessInfoType>(GetReg32(system, 2)); 2020 info_type = Convert<ProcessInfoType>(GetArg32(args, 2));
2021 2021
2022 ret = GetProcessInfo64From32(system, std::addressof(out_info), process_handle, info_type); 2022 ret = GetProcessInfo64From32(system, std::addressof(out_info), process_handle, info_type);
2023 2023
2024 SetReg32(system, 0, Convert<uint32_t>(ret)); 2024 SetArg32(args, 0, Convert<uint32_t>(ret));
2025 auto out_info_scatter = Convert<std::array<uint32_t, 2>>(out_info); 2025 auto out_info_scatter = Convert<std::array<uint32_t, 2>>(out_info);
2026 SetReg32(system, 1, out_info_scatter[0]); 2026 SetArg32(args, 1, out_info_scatter[0]);
2027 SetReg32(system, 2, out_info_scatter[1]); 2027 SetArg32(args, 2, out_info_scatter[1]);
2028} 2028}
2029 2029
2030static void SvcWrap_CreateResourceLimit64From32(Core::System& system) { 2030static void SvcWrap_CreateResourceLimit64From32(Core::System& system, std::span<uint64_t, 8> args) {
2031 Result ret{}; 2031 Result ret{};
2032 2032
2033 Handle out_handle{}; 2033 Handle out_handle{};
2034 2034
2035 ret = CreateResourceLimit64From32(system, std::addressof(out_handle)); 2035 ret = CreateResourceLimit64From32(system, std::addressof(out_handle));
2036 2036
2037 SetReg32(system, 0, Convert<uint32_t>(ret)); 2037 SetArg32(args, 0, Convert<uint32_t>(ret));
2038 SetReg32(system, 1, Convert<uint32_t>(out_handle)); 2038 SetArg32(args, 1, Convert<uint32_t>(out_handle));
2039} 2039}
2040 2040
2041static void SvcWrap_SetResourceLimitLimitValue64From32(Core::System& system) { 2041static void SvcWrap_SetResourceLimitLimitValue64From32(Core::System& system, std::span<uint64_t, 8> args) {
2042 Result ret{}; 2042 Result ret{};
2043 2043
2044 Handle resource_limit_handle{}; 2044 Handle resource_limit_handle{};
2045 LimitableResource which{}; 2045 LimitableResource which{};
2046 int64_t limit_value{}; 2046 int64_t limit_value{};
2047 2047
2048 resource_limit_handle = Convert<Handle>(GetReg32(system, 0)); 2048 resource_limit_handle = Convert<Handle>(GetArg32(args, 0));
2049 which = Convert<LimitableResource>(GetReg32(system, 1)); 2049 which = Convert<LimitableResource>(GetArg32(args, 1));
2050 std::array<uint32_t, 2> limit_value_gather{}; 2050 std::array<uint32_t, 2> limit_value_gather{};
2051 limit_value_gather[0] = GetReg32(system, 2); 2051 limit_value_gather[0] = GetArg32(args, 2);
2052 limit_value_gather[1] = GetReg32(system, 3); 2052 limit_value_gather[1] = GetArg32(args, 3);
2053 limit_value = Convert<int64_t>(limit_value_gather); 2053 limit_value = Convert<int64_t>(limit_value_gather);
2054 2054
2055 ret = SetResourceLimitLimitValue64From32(system, resource_limit_handle, which, limit_value); 2055 ret = SetResourceLimitLimitValue64From32(system, resource_limit_handle, which, limit_value);
2056 2056
2057 SetReg32(system, 0, Convert<uint32_t>(ret)); 2057 SetArg32(args, 0, Convert<uint32_t>(ret));
2058} 2058}
2059 2059
2060static void SvcWrap_MapInsecureMemory64From32(Core::System& system) { 2060static void SvcWrap_MapInsecureMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
2061 Result ret{}; 2061 Result ret{};
2062 2062
2063 uint32_t address{}; 2063 uint32_t address{};
2064 uint32_t size{}; 2064 uint32_t size{};
2065 2065
2066 address = Convert<uint32_t>(GetReg32(system, 0)); 2066 address = Convert<uint32_t>(GetArg32(args, 0));
2067 size = Convert<uint32_t>(GetReg32(system, 1)); 2067 size = Convert<uint32_t>(GetArg32(args, 1));
2068 2068
2069 ret = MapInsecureMemory64From32(system, address, size); 2069 ret = MapInsecureMemory64From32(system, address, size);
2070 2070
2071 SetReg32(system, 0, Convert<uint32_t>(ret)); 2071 SetArg32(args, 0, Convert<uint32_t>(ret));
2072} 2072}
2073 2073
2074static void SvcWrap_UnmapInsecureMemory64From32(Core::System& system) { 2074static void SvcWrap_UnmapInsecureMemory64From32(Core::System& system, std::span<uint64_t, 8> args) {
2075 Result ret{}; 2075 Result ret{};
2076 2076
2077 uint32_t address{}; 2077 uint32_t address{};
2078 uint32_t size{}; 2078 uint32_t size{};
2079 2079
2080 address = Convert<uint32_t>(GetReg32(system, 0)); 2080 address = Convert<uint32_t>(GetArg32(args, 0));
2081 size = Convert<uint32_t>(GetReg32(system, 1)); 2081 size = Convert<uint32_t>(GetArg32(args, 1));
2082 2082
2083 ret = UnmapInsecureMemory64From32(system, address, size); 2083 ret = UnmapInsecureMemory64From32(system, address, size);
2084 2084
2085 SetReg32(system, 0, Convert<uint32_t>(ret)); 2085 SetArg32(args, 0, Convert<uint32_t>(ret));
2086} 2086}
2087 2087
2088static void SvcWrap_SetHeapSize64(Core::System& system) { 2088static void SvcWrap_SetHeapSize64(Core::System& system, std::span<uint64_t, 8> args) {
2089 Result ret{}; 2089 Result ret{};
2090 2090
2091 uint64_t out_address{}; 2091 uint64_t out_address{};
2092 uint64_t size{}; 2092 uint64_t size{};
2093 2093
2094 size = Convert<uint64_t>(GetReg64(system, 1)); 2094 size = Convert<uint64_t>(GetArg64(args, 1));
2095 2095
2096 ret = SetHeapSize64(system, std::addressof(out_address), size); 2096 ret = SetHeapSize64(system, std::addressof(out_address), size);
2097 2097
2098 SetReg64(system, 0, Convert<uint64_t>(ret)); 2098 SetArg64(args, 0, Convert<uint64_t>(ret));
2099 SetReg64(system, 1, Convert<uint64_t>(out_address)); 2099 SetArg64(args, 1, Convert<uint64_t>(out_address));
2100} 2100}
2101 2101
2102static void SvcWrap_SetMemoryPermission64(Core::System& system) { 2102static void SvcWrap_SetMemoryPermission64(Core::System& system, std::span<uint64_t, 8> args) {
2103 Result ret{}; 2103 Result ret{};
2104 2104
2105 uint64_t address{}; 2105 uint64_t address{};
2106 uint64_t size{}; 2106 uint64_t size{};
2107 MemoryPermission perm{}; 2107 MemoryPermission perm{};
2108 2108
2109 address = Convert<uint64_t>(GetReg64(system, 0)); 2109 address = Convert<uint64_t>(GetArg64(args, 0));
2110 size = Convert<uint64_t>(GetReg64(system, 1)); 2110 size = Convert<uint64_t>(GetArg64(args, 1));
2111 perm = Convert<MemoryPermission>(GetReg64(system, 2)); 2111 perm = Convert<MemoryPermission>(GetArg64(args, 2));
2112 2112
2113 ret = SetMemoryPermission64(system, address, size, perm); 2113 ret = SetMemoryPermission64(system, address, size, perm);
2114 2114
2115 SetReg64(system, 0, Convert<uint64_t>(ret)); 2115 SetArg64(args, 0, Convert<uint64_t>(ret));
2116} 2116}
2117 2117
2118static void SvcWrap_SetMemoryAttribute64(Core::System& system) { 2118static void SvcWrap_SetMemoryAttribute64(Core::System& system, std::span<uint64_t, 8> args) {
2119 Result ret{}; 2119 Result ret{};
2120 2120
2121 uint64_t address{}; 2121 uint64_t address{};
@@ -2123,69 +2123,69 @@ static void SvcWrap_SetMemoryAttribute64(Core::System& system) {
2123 uint32_t mask{}; 2123 uint32_t mask{};
2124 uint32_t attr{}; 2124 uint32_t attr{};
2125 2125
2126 address = Convert<uint64_t>(GetReg64(system, 0)); 2126 address = Convert<uint64_t>(GetArg64(args, 0));
2127 size = Convert<uint64_t>(GetReg64(system, 1)); 2127 size = Convert<uint64_t>(GetArg64(args, 1));
2128 mask = Convert<uint32_t>(GetReg64(system, 2)); 2128 mask = Convert<uint32_t>(GetArg64(args, 2));
2129 attr = Convert<uint32_t>(GetReg64(system, 3)); 2129 attr = Convert<uint32_t>(GetArg64(args, 3));
2130 2130
2131 ret = SetMemoryAttribute64(system, address, size, mask, attr); 2131 ret = SetMemoryAttribute64(system, address, size, mask, attr);
2132 2132
2133 SetReg64(system, 0, Convert<uint64_t>(ret)); 2133 SetArg64(args, 0, Convert<uint64_t>(ret));
2134} 2134}
2135 2135
2136static void SvcWrap_MapMemory64(Core::System& system) { 2136static void SvcWrap_MapMemory64(Core::System& system, std::span<uint64_t, 8> args) {
2137 Result ret{}; 2137 Result ret{};
2138 2138
2139 uint64_t dst_address{}; 2139 uint64_t dst_address{};
2140 uint64_t src_address{}; 2140 uint64_t src_address{};
2141 uint64_t size{}; 2141 uint64_t size{};
2142 2142
2143 dst_address = Convert<uint64_t>(GetReg64(system, 0)); 2143 dst_address = Convert<uint64_t>(GetArg64(args, 0));
2144 src_address = Convert<uint64_t>(GetReg64(system, 1)); 2144 src_address = Convert<uint64_t>(GetArg64(args, 1));
2145 size = Convert<uint64_t>(GetReg64(system, 2)); 2145 size = Convert<uint64_t>(GetArg64(args, 2));
2146 2146
2147 ret = MapMemory64(system, dst_address, src_address, size); 2147 ret = MapMemory64(system, dst_address, src_address, size);
2148 2148
2149 SetReg64(system, 0, Convert<uint64_t>(ret)); 2149 SetArg64(args, 0, Convert<uint64_t>(ret));
2150} 2150}
2151 2151
2152static void SvcWrap_UnmapMemory64(Core::System& system) { 2152static void SvcWrap_UnmapMemory64(Core::System& system, std::span<uint64_t, 8> args) {
2153 Result ret{}; 2153 Result ret{};
2154 2154
2155 uint64_t dst_address{}; 2155 uint64_t dst_address{};
2156 uint64_t src_address{}; 2156 uint64_t src_address{};
2157 uint64_t size{}; 2157 uint64_t size{};
2158 2158
2159 dst_address = Convert<uint64_t>(GetReg64(system, 0)); 2159 dst_address = Convert<uint64_t>(GetArg64(args, 0));
2160 src_address = Convert<uint64_t>(GetReg64(system, 1)); 2160 src_address = Convert<uint64_t>(GetArg64(args, 1));
2161 size = Convert<uint64_t>(GetReg64(system, 2)); 2161 size = Convert<uint64_t>(GetArg64(args, 2));
2162 2162
2163 ret = UnmapMemory64(system, dst_address, src_address, size); 2163 ret = UnmapMemory64(system, dst_address, src_address, size);
2164 2164
2165 SetReg64(system, 0, Convert<uint64_t>(ret)); 2165 SetArg64(args, 0, Convert<uint64_t>(ret));
2166} 2166}
2167 2167
2168static void SvcWrap_QueryMemory64(Core::System& system) { 2168static void SvcWrap_QueryMemory64(Core::System& system, std::span<uint64_t, 8> args) {
2169 Result ret{}; 2169 Result ret{};
2170 2170
2171 PageInfo out_page_info{}; 2171 PageInfo out_page_info{};
2172 uint64_t out_memory_info{}; 2172 uint64_t out_memory_info{};
2173 uint64_t address{}; 2173 uint64_t address{};
2174 2174
2175 out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); 2175 out_memory_info = Convert<uint64_t>(GetArg64(args, 0));
2176 address = Convert<uint64_t>(GetReg64(system, 2)); 2176 address = Convert<uint64_t>(GetArg64(args, 2));
2177 2177
2178 ret = QueryMemory64(system, out_memory_info, std::addressof(out_page_info), address); 2178 ret = QueryMemory64(system, out_memory_info, std::addressof(out_page_info), address);
2179 2179
2180 SetReg64(system, 0, Convert<uint64_t>(ret)); 2180 SetArg64(args, 0, Convert<uint64_t>(ret));
2181 SetReg64(system, 1, Convert<uint64_t>(out_page_info)); 2181 SetArg64(args, 1, Convert<uint64_t>(out_page_info));
2182} 2182}
2183 2183
2184static void SvcWrap_ExitProcess64(Core::System& system) { 2184static void SvcWrap_ExitProcess64(Core::System& system, std::span<uint64_t, 8> args) {
2185 ExitProcess64(system); 2185 ExitProcess64(system);
2186} 2186}
2187 2187
2188static void SvcWrap_CreateThread64(Core::System& system) { 2188static void SvcWrap_CreateThread64(Core::System& system, std::span<uint64_t, 8> args) {
2189 Result ret{}; 2189 Result ret{};
2190 2190
2191 Handle out_handle{}; 2191 Handle out_handle{};
@@ -2195,135 +2195,135 @@ static void SvcWrap_CreateThread64(Core::System& system) {
2195 int32_t priority{}; 2195 int32_t priority{};
2196 int32_t core_id{}; 2196 int32_t core_id{};
2197 2197
2198 func = Convert<uint64_t>(GetReg64(system, 1)); 2198 func = Convert<uint64_t>(GetArg64(args, 1));
2199 arg = Convert<uint64_t>(GetReg64(system, 2)); 2199 arg = Convert<uint64_t>(GetArg64(args, 2));
2200 stack_bottom = Convert<uint64_t>(GetReg64(system, 3)); 2200 stack_bottom = Convert<uint64_t>(GetArg64(args, 3));
2201 priority = Convert<int32_t>(GetReg64(system, 4)); 2201 priority = Convert<int32_t>(GetArg64(args, 4));
2202 core_id = Convert<int32_t>(GetReg64(system, 5)); 2202 core_id = Convert<int32_t>(GetArg64(args, 5));
2203 2203
2204 ret = CreateThread64(system, std::addressof(out_handle), func, arg, stack_bottom, priority, core_id); 2204 ret = CreateThread64(system, std::addressof(out_handle), func, arg, stack_bottom, priority, core_id);
2205 2205
2206 SetReg64(system, 0, Convert<uint64_t>(ret)); 2206 SetArg64(args, 0, Convert<uint64_t>(ret));
2207 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 2207 SetArg64(args, 1, Convert<uint64_t>(out_handle));
2208} 2208}
2209 2209
2210static void SvcWrap_StartThread64(Core::System& system) { 2210static void SvcWrap_StartThread64(Core::System& system, std::span<uint64_t, 8> args) {
2211 Result ret{}; 2211 Result ret{};
2212 2212
2213 Handle thread_handle{}; 2213 Handle thread_handle{};
2214 2214
2215 thread_handle = Convert<Handle>(GetReg64(system, 0)); 2215 thread_handle = Convert<Handle>(GetArg64(args, 0));
2216 2216
2217 ret = StartThread64(system, thread_handle); 2217 ret = StartThread64(system, thread_handle);
2218 2218
2219 SetReg64(system, 0, Convert<uint64_t>(ret)); 2219 SetArg64(args, 0, Convert<uint64_t>(ret));
2220} 2220}
2221 2221
2222static void SvcWrap_ExitThread64(Core::System& system) { 2222static void SvcWrap_ExitThread64(Core::System& system, std::span<uint64_t, 8> args) {
2223 ExitThread64(system); 2223 ExitThread64(system);
2224} 2224}
2225 2225
2226static void SvcWrap_SleepThread64(Core::System& system) { 2226static void SvcWrap_SleepThread64(Core::System& system, std::span<uint64_t, 8> args) {
2227 int64_t ns{}; 2227 int64_t ns{};
2228 2228
2229 ns = Convert<int64_t>(GetReg64(system, 0)); 2229 ns = Convert<int64_t>(GetArg64(args, 0));
2230 2230
2231 SleepThread64(system, ns); 2231 SleepThread64(system, ns);
2232} 2232}
2233 2233
2234static void SvcWrap_GetThreadPriority64(Core::System& system) { 2234static void SvcWrap_GetThreadPriority64(Core::System& system, std::span<uint64_t, 8> args) {
2235 Result ret{}; 2235 Result ret{};
2236 2236
2237 int32_t out_priority{}; 2237 int32_t out_priority{};
2238 Handle thread_handle{}; 2238 Handle thread_handle{};
2239 2239
2240 thread_handle = Convert<Handle>(GetReg64(system, 1)); 2240 thread_handle = Convert<Handle>(GetArg64(args, 1));
2241 2241
2242 ret = GetThreadPriority64(system, std::addressof(out_priority), thread_handle); 2242 ret = GetThreadPriority64(system, std::addressof(out_priority), thread_handle);
2243 2243
2244 SetReg64(system, 0, Convert<uint64_t>(ret)); 2244 SetArg64(args, 0, Convert<uint64_t>(ret));
2245 SetReg64(system, 1, Convert<uint64_t>(out_priority)); 2245 SetArg64(args, 1, Convert<uint64_t>(out_priority));
2246} 2246}
2247 2247
2248static void SvcWrap_SetThreadPriority64(Core::System& system) { 2248static void SvcWrap_SetThreadPriority64(Core::System& system, std::span<uint64_t, 8> args) {
2249 Result ret{}; 2249 Result ret{};
2250 2250
2251 Handle thread_handle{}; 2251 Handle thread_handle{};
2252 int32_t priority{}; 2252 int32_t priority{};
2253 2253
2254 thread_handle = Convert<Handle>(GetReg64(system, 0)); 2254 thread_handle = Convert<Handle>(GetArg64(args, 0));
2255 priority = Convert<int32_t>(GetReg64(system, 1)); 2255 priority = Convert<int32_t>(GetArg64(args, 1));
2256 2256
2257 ret = SetThreadPriority64(system, thread_handle, priority); 2257 ret = SetThreadPriority64(system, thread_handle, priority);
2258 2258
2259 SetReg64(system, 0, Convert<uint64_t>(ret)); 2259 SetArg64(args, 0, Convert<uint64_t>(ret));
2260} 2260}
2261 2261
2262static void SvcWrap_GetThreadCoreMask64(Core::System& system) { 2262static void SvcWrap_GetThreadCoreMask64(Core::System& system, std::span<uint64_t, 8> args) {
2263 Result ret{}; 2263 Result ret{};
2264 2264
2265 int32_t out_core_id{}; 2265 int32_t out_core_id{};
2266 uint64_t out_affinity_mask{}; 2266 uint64_t out_affinity_mask{};
2267 Handle thread_handle{}; 2267 Handle thread_handle{};
2268 2268
2269 thread_handle = Convert<Handle>(GetReg64(system, 2)); 2269 thread_handle = Convert<Handle>(GetArg64(args, 2));
2270 2270
2271 ret = GetThreadCoreMask64(system, std::addressof(out_core_id), std::addressof(out_affinity_mask), thread_handle); 2271 ret = GetThreadCoreMask64(system, std::addressof(out_core_id), std::addressof(out_affinity_mask), thread_handle);
2272 2272
2273 SetReg64(system, 0, Convert<uint64_t>(ret)); 2273 SetArg64(args, 0, Convert<uint64_t>(ret));
2274 SetReg64(system, 1, Convert<uint64_t>(out_core_id)); 2274 SetArg64(args, 1, Convert<uint64_t>(out_core_id));
2275 SetReg64(system, 2, Convert<uint64_t>(out_affinity_mask)); 2275 SetArg64(args, 2, Convert<uint64_t>(out_affinity_mask));
2276} 2276}
2277 2277
2278static void SvcWrap_SetThreadCoreMask64(Core::System& system) { 2278static void SvcWrap_SetThreadCoreMask64(Core::System& system, std::span<uint64_t, 8> args) {
2279 Result ret{}; 2279 Result ret{};
2280 2280
2281 Handle thread_handle{}; 2281 Handle thread_handle{};
2282 int32_t core_id{}; 2282 int32_t core_id{};
2283 uint64_t affinity_mask{}; 2283 uint64_t affinity_mask{};
2284 2284
2285 thread_handle = Convert<Handle>(GetReg64(system, 0)); 2285 thread_handle = Convert<Handle>(GetArg64(args, 0));
2286 core_id = Convert<int32_t>(GetReg64(system, 1)); 2286 core_id = Convert<int32_t>(GetArg64(args, 1));
2287 affinity_mask = Convert<uint64_t>(GetReg64(system, 2)); 2287 affinity_mask = Convert<uint64_t>(GetArg64(args, 2));
2288 2288
2289 ret = SetThreadCoreMask64(system, thread_handle, core_id, affinity_mask); 2289 ret = SetThreadCoreMask64(system, thread_handle, core_id, affinity_mask);
2290 2290
2291 SetReg64(system, 0, Convert<uint64_t>(ret)); 2291 SetArg64(args, 0, Convert<uint64_t>(ret));
2292} 2292}
2293 2293
2294static void SvcWrap_GetCurrentProcessorNumber64(Core::System& system) { 2294static void SvcWrap_GetCurrentProcessorNumber64(Core::System& system, std::span<uint64_t, 8> args) {
2295 int32_t ret{}; 2295 int32_t ret{};
2296 2296
2297 ret = GetCurrentProcessorNumber64(system); 2297 ret = GetCurrentProcessorNumber64(system);
2298 2298
2299 SetReg64(system, 0, Convert<uint64_t>(ret)); 2299 SetArg64(args, 0, Convert<uint64_t>(ret));
2300} 2300}
2301 2301
2302static void SvcWrap_SignalEvent64(Core::System& system) { 2302static void SvcWrap_SignalEvent64(Core::System& system, std::span<uint64_t, 8> args) {
2303 Result ret{}; 2303 Result ret{};
2304 2304
2305 Handle event_handle{}; 2305 Handle event_handle{};
2306 2306
2307 event_handle = Convert<Handle>(GetReg64(system, 0)); 2307 event_handle = Convert<Handle>(GetArg64(args, 0));
2308 2308
2309 ret = SignalEvent64(system, event_handle); 2309 ret = SignalEvent64(system, event_handle);
2310 2310
2311 SetReg64(system, 0, Convert<uint64_t>(ret)); 2311 SetArg64(args, 0, Convert<uint64_t>(ret));
2312} 2312}
2313 2313
2314static void SvcWrap_ClearEvent64(Core::System& system) { 2314static void SvcWrap_ClearEvent64(Core::System& system, std::span<uint64_t, 8> args) {
2315 Result ret{}; 2315 Result ret{};
2316 2316
2317 Handle event_handle{}; 2317 Handle event_handle{};
2318 2318
2319 event_handle = Convert<Handle>(GetReg64(system, 0)); 2319 event_handle = Convert<Handle>(GetArg64(args, 0));
2320 2320
2321 ret = ClearEvent64(system, event_handle); 2321 ret = ClearEvent64(system, event_handle);
2322 2322
2323 SetReg64(system, 0, Convert<uint64_t>(ret)); 2323 SetArg64(args, 0, Convert<uint64_t>(ret));
2324} 2324}
2325 2325
2326static void SvcWrap_MapSharedMemory64(Core::System& system) { 2326static void SvcWrap_MapSharedMemory64(Core::System& system, std::span<uint64_t, 8> args) {
2327 Result ret{}; 2327 Result ret{};
2328 2328
2329 Handle shmem_handle{}; 2329 Handle shmem_handle{};
@@ -2331,33 +2331,33 @@ static void SvcWrap_MapSharedMemory64(Core::System& system) {
2331 uint64_t size{}; 2331 uint64_t size{};
2332 MemoryPermission map_perm{}; 2332 MemoryPermission map_perm{};
2333 2333
2334 shmem_handle = Convert<Handle>(GetReg64(system, 0)); 2334 shmem_handle = Convert<Handle>(GetArg64(args, 0));
2335 address = Convert<uint64_t>(GetReg64(system, 1)); 2335 address = Convert<uint64_t>(GetArg64(args, 1));
2336 size = Convert<uint64_t>(GetReg64(system, 2)); 2336 size = Convert<uint64_t>(GetArg64(args, 2));
2337 map_perm = Convert<MemoryPermission>(GetReg64(system, 3)); 2337 map_perm = Convert<MemoryPermission>(GetArg64(args, 3));
2338 2338
2339 ret = MapSharedMemory64(system, shmem_handle, address, size, map_perm); 2339 ret = MapSharedMemory64(system, shmem_handle, address, size, map_perm);
2340 2340
2341 SetReg64(system, 0, Convert<uint64_t>(ret)); 2341 SetArg64(args, 0, Convert<uint64_t>(ret));
2342} 2342}
2343 2343
2344static void SvcWrap_UnmapSharedMemory64(Core::System& system) { 2344static void SvcWrap_UnmapSharedMemory64(Core::System& system, std::span<uint64_t, 8> args) {
2345 Result ret{}; 2345 Result ret{};
2346 2346
2347 Handle shmem_handle{}; 2347 Handle shmem_handle{};
2348 uint64_t address{}; 2348 uint64_t address{};
2349 uint64_t size{}; 2349 uint64_t size{};
2350 2350
2351 shmem_handle = Convert<Handle>(GetReg64(system, 0)); 2351 shmem_handle = Convert<Handle>(GetArg64(args, 0));
2352 address = Convert<uint64_t>(GetReg64(system, 1)); 2352 address = Convert<uint64_t>(GetArg64(args, 1));
2353 size = Convert<uint64_t>(GetReg64(system, 2)); 2353 size = Convert<uint64_t>(GetArg64(args, 2));
2354 2354
2355 ret = UnmapSharedMemory64(system, shmem_handle, address, size); 2355 ret = UnmapSharedMemory64(system, shmem_handle, address, size);
2356 2356
2357 SetReg64(system, 0, Convert<uint64_t>(ret)); 2357 SetArg64(args, 0, Convert<uint64_t>(ret));
2358} 2358}
2359 2359
2360static void SvcWrap_CreateTransferMemory64(Core::System& system) { 2360static void SvcWrap_CreateTransferMemory64(Core::System& system, std::span<uint64_t, 8> args) {
2361 Result ret{}; 2361 Result ret{};
2362 2362
2363 Handle out_handle{}; 2363 Handle out_handle{};
@@ -2365,41 +2365,41 @@ static void SvcWrap_CreateTransferMemory64(Core::System& system) {
2365 uint64_t size{}; 2365 uint64_t size{};
2366 MemoryPermission map_perm{}; 2366 MemoryPermission map_perm{};
2367 2367
2368 address = Convert<uint64_t>(GetReg64(system, 1)); 2368 address = Convert<uint64_t>(GetArg64(args, 1));
2369 size = Convert<uint64_t>(GetReg64(system, 2)); 2369 size = Convert<uint64_t>(GetArg64(args, 2));
2370 map_perm = Convert<MemoryPermission>(GetReg64(system, 3)); 2370 map_perm = Convert<MemoryPermission>(GetArg64(args, 3));
2371 2371
2372 ret = CreateTransferMemory64(system, std::addressof(out_handle), address, size, map_perm); 2372 ret = CreateTransferMemory64(system, std::addressof(out_handle), address, size, map_perm);
2373 2373
2374 SetReg64(system, 0, Convert<uint64_t>(ret)); 2374 SetArg64(args, 0, Convert<uint64_t>(ret));
2375 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 2375 SetArg64(args, 1, Convert<uint64_t>(out_handle));
2376} 2376}
2377 2377
2378static void SvcWrap_CloseHandle64(Core::System& system) { 2378static void SvcWrap_CloseHandle64(Core::System& system, std::span<uint64_t, 8> args) {
2379 Result ret{}; 2379 Result ret{};
2380 2380
2381 Handle handle{}; 2381 Handle handle{};
2382 2382
2383 handle = Convert<Handle>(GetReg64(system, 0)); 2383 handle = Convert<Handle>(GetArg64(args, 0));
2384 2384
2385 ret = CloseHandle64(system, handle); 2385 ret = CloseHandle64(system, handle);
2386 2386
2387 SetReg64(system, 0, Convert<uint64_t>(ret)); 2387 SetArg64(args, 0, Convert<uint64_t>(ret));
2388} 2388}
2389 2389
2390static void SvcWrap_ResetSignal64(Core::System& system) { 2390static void SvcWrap_ResetSignal64(Core::System& system, std::span<uint64_t, 8> args) {
2391 Result ret{}; 2391 Result ret{};
2392 2392
2393 Handle handle{}; 2393 Handle handle{};
2394 2394
2395 handle = Convert<Handle>(GetReg64(system, 0)); 2395 handle = Convert<Handle>(GetArg64(args, 0));
2396 2396
2397 ret = ResetSignal64(system, handle); 2397 ret = ResetSignal64(system, handle);
2398 2398
2399 SetReg64(system, 0, Convert<uint64_t>(ret)); 2399 SetArg64(args, 0, Convert<uint64_t>(ret));
2400} 2400}
2401 2401
2402static void SvcWrap_WaitSynchronization64(Core::System& system) { 2402static void SvcWrap_WaitSynchronization64(Core::System& system, std::span<uint64_t, 8> args) {
2403 Result ret{}; 2403 Result ret{};
2404 2404
2405 int32_t out_index{}; 2405 int32_t out_index{};
@@ -2407,57 +2407,57 @@ static void SvcWrap_WaitSynchronization64(Core::System& system) {
2407 int32_t num_handles{}; 2407 int32_t num_handles{};
2408 int64_t timeout_ns{}; 2408 int64_t timeout_ns{};
2409 2409
2410 handles = Convert<uint64_t>(GetReg64(system, 1)); 2410 handles = Convert<uint64_t>(GetArg64(args, 1));
2411 num_handles = Convert<int32_t>(GetReg64(system, 2)); 2411 num_handles = Convert<int32_t>(GetArg64(args, 2));
2412 timeout_ns = Convert<int64_t>(GetReg64(system, 3)); 2412 timeout_ns = Convert<int64_t>(GetArg64(args, 3));
2413 2413
2414 ret = WaitSynchronization64(system, std::addressof(out_index), handles, num_handles, timeout_ns); 2414 ret = WaitSynchronization64(system, std::addressof(out_index), handles, num_handles, timeout_ns);
2415 2415
2416 SetReg64(system, 0, Convert<uint64_t>(ret)); 2416 SetArg64(args, 0, Convert<uint64_t>(ret));
2417 SetReg64(system, 1, Convert<uint64_t>(out_index)); 2417 SetArg64(args, 1, Convert<uint64_t>(out_index));
2418} 2418}
2419 2419
2420static void SvcWrap_CancelSynchronization64(Core::System& system) { 2420static void SvcWrap_CancelSynchronization64(Core::System& system, std::span<uint64_t, 8> args) {
2421 Result ret{}; 2421 Result ret{};
2422 2422
2423 Handle handle{}; 2423 Handle handle{};
2424 2424
2425 handle = Convert<Handle>(GetReg64(system, 0)); 2425 handle = Convert<Handle>(GetArg64(args, 0));
2426 2426
2427 ret = CancelSynchronization64(system, handle); 2427 ret = CancelSynchronization64(system, handle);
2428 2428
2429 SetReg64(system, 0, Convert<uint64_t>(ret)); 2429 SetArg64(args, 0, Convert<uint64_t>(ret));
2430} 2430}
2431 2431
2432static void SvcWrap_ArbitrateLock64(Core::System& system) { 2432static void SvcWrap_ArbitrateLock64(Core::System& system, std::span<uint64_t, 8> args) {
2433 Result ret{}; 2433 Result ret{};
2434 2434
2435 Handle thread_handle{}; 2435 Handle thread_handle{};
2436 uint64_t address{}; 2436 uint64_t address{};
2437 uint32_t tag{}; 2437 uint32_t tag{};
2438 2438
2439 thread_handle = Convert<Handle>(GetReg64(system, 0)); 2439 thread_handle = Convert<Handle>(GetArg64(args, 0));
2440 address = Convert<uint64_t>(GetReg64(system, 1)); 2440 address = Convert<uint64_t>(GetArg64(args, 1));
2441 tag = Convert<uint32_t>(GetReg64(system, 2)); 2441 tag = Convert<uint32_t>(GetArg64(args, 2));
2442 2442
2443 ret = ArbitrateLock64(system, thread_handle, address, tag); 2443 ret = ArbitrateLock64(system, thread_handle, address, tag);
2444 2444
2445 SetReg64(system, 0, Convert<uint64_t>(ret)); 2445 SetArg64(args, 0, Convert<uint64_t>(ret));
2446} 2446}
2447 2447
2448static void SvcWrap_ArbitrateUnlock64(Core::System& system) { 2448static void SvcWrap_ArbitrateUnlock64(Core::System& system, std::span<uint64_t, 8> args) {
2449 Result ret{}; 2449 Result ret{};
2450 2450
2451 uint64_t address{}; 2451 uint64_t address{};
2452 2452
2453 address = Convert<uint64_t>(GetReg64(system, 0)); 2453 address = Convert<uint64_t>(GetArg64(args, 0));
2454 2454
2455 ret = ArbitrateUnlock64(system, address); 2455 ret = ArbitrateUnlock64(system, address);
2456 2456
2457 SetReg64(system, 0, Convert<uint64_t>(ret)); 2457 SetArg64(args, 0, Convert<uint64_t>(ret));
2458} 2458}
2459 2459
2460static void SvcWrap_WaitProcessWideKeyAtomic64(Core::System& system) { 2460static void SvcWrap_WaitProcessWideKeyAtomic64(Core::System& system, std::span<uint64_t, 8> args) {
2461 Result ret{}; 2461 Result ret{};
2462 2462
2463 uint64_t address{}; 2463 uint64_t address{};
@@ -2465,77 +2465,77 @@ static void SvcWrap_WaitProcessWideKeyAtomic64(Core::System& system) {
2465 uint32_t tag{}; 2465 uint32_t tag{};
2466 int64_t timeout_ns{}; 2466 int64_t timeout_ns{};
2467 2467
2468 address = Convert<uint64_t>(GetReg64(system, 0)); 2468 address = Convert<uint64_t>(GetArg64(args, 0));
2469 cv_key = Convert<uint64_t>(GetReg64(system, 1)); 2469 cv_key = Convert<uint64_t>(GetArg64(args, 1));
2470 tag = Convert<uint32_t>(GetReg64(system, 2)); 2470 tag = Convert<uint32_t>(GetArg64(args, 2));
2471 timeout_ns = Convert<int64_t>(GetReg64(system, 3)); 2471 timeout_ns = Convert<int64_t>(GetArg64(args, 3));
2472 2472
2473 ret = WaitProcessWideKeyAtomic64(system, address, cv_key, tag, timeout_ns); 2473 ret = WaitProcessWideKeyAtomic64(system, address, cv_key, tag, timeout_ns);
2474 2474
2475 SetReg64(system, 0, Convert<uint64_t>(ret)); 2475 SetArg64(args, 0, Convert<uint64_t>(ret));
2476} 2476}
2477 2477
2478static void SvcWrap_SignalProcessWideKey64(Core::System& system) { 2478static void SvcWrap_SignalProcessWideKey64(Core::System& system, std::span<uint64_t, 8> args) {
2479 uint64_t cv_key{}; 2479 uint64_t cv_key{};
2480 int32_t count{}; 2480 int32_t count{};
2481 2481
2482 cv_key = Convert<uint64_t>(GetReg64(system, 0)); 2482 cv_key = Convert<uint64_t>(GetArg64(args, 0));
2483 count = Convert<int32_t>(GetReg64(system, 1)); 2483 count = Convert<int32_t>(GetArg64(args, 1));
2484 2484
2485 SignalProcessWideKey64(system, cv_key, count); 2485 SignalProcessWideKey64(system, cv_key, count);
2486} 2486}
2487 2487
2488static void SvcWrap_GetSystemTick64(Core::System& system) { 2488static void SvcWrap_GetSystemTick64(Core::System& system, std::span<uint64_t, 8> args) {
2489 int64_t ret{}; 2489 int64_t ret{};
2490 2490
2491 ret = GetSystemTick64(system); 2491 ret = GetSystemTick64(system);
2492 2492
2493 SetReg64(system, 0, Convert<uint64_t>(ret)); 2493 SetArg64(args, 0, Convert<uint64_t>(ret));
2494} 2494}
2495 2495
2496static void SvcWrap_ConnectToNamedPort64(Core::System& system) { 2496static void SvcWrap_ConnectToNamedPort64(Core::System& system, std::span<uint64_t, 8> args) {
2497 Result ret{}; 2497 Result ret{};
2498 2498
2499 Handle out_handle{}; 2499 Handle out_handle{};
2500 uint64_t name{}; 2500 uint64_t name{};
2501 2501
2502 name = Convert<uint64_t>(GetReg64(system, 1)); 2502 name = Convert<uint64_t>(GetArg64(args, 1));
2503 2503
2504 ret = ConnectToNamedPort64(system, std::addressof(out_handle), name); 2504 ret = ConnectToNamedPort64(system, std::addressof(out_handle), name);
2505 2505
2506 SetReg64(system, 0, Convert<uint64_t>(ret)); 2506 SetArg64(args, 0, Convert<uint64_t>(ret));
2507 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 2507 SetArg64(args, 1, Convert<uint64_t>(out_handle));
2508} 2508}
2509 2509
2510static void SvcWrap_SendSyncRequest64(Core::System& system) { 2510static void SvcWrap_SendSyncRequest64(Core::System& system, std::span<uint64_t, 8> args) {
2511 Result ret{}; 2511 Result ret{};
2512 2512
2513 Handle session_handle{}; 2513 Handle session_handle{};
2514 2514
2515 session_handle = Convert<Handle>(GetReg64(system, 0)); 2515 session_handle = Convert<Handle>(GetArg64(args, 0));
2516 2516
2517 ret = SendSyncRequest64(system, session_handle); 2517 ret = SendSyncRequest64(system, session_handle);
2518 2518
2519 SetReg64(system, 0, Convert<uint64_t>(ret)); 2519 SetArg64(args, 0, Convert<uint64_t>(ret));
2520} 2520}
2521 2521
2522static void SvcWrap_SendSyncRequestWithUserBuffer64(Core::System& system) { 2522static void SvcWrap_SendSyncRequestWithUserBuffer64(Core::System& system, std::span<uint64_t, 8> args) {
2523 Result ret{}; 2523 Result ret{};
2524 2524
2525 uint64_t message_buffer{}; 2525 uint64_t message_buffer{};
2526 uint64_t message_buffer_size{}; 2526 uint64_t message_buffer_size{};
2527 Handle session_handle{}; 2527 Handle session_handle{};
2528 2528
2529 message_buffer = Convert<uint64_t>(GetReg64(system, 0)); 2529 message_buffer = Convert<uint64_t>(GetArg64(args, 0));
2530 message_buffer_size = Convert<uint64_t>(GetReg64(system, 1)); 2530 message_buffer_size = Convert<uint64_t>(GetArg64(args, 1));
2531 session_handle = Convert<Handle>(GetReg64(system, 2)); 2531 session_handle = Convert<Handle>(GetArg64(args, 2));
2532 2532
2533 ret = SendSyncRequestWithUserBuffer64(system, message_buffer, message_buffer_size, session_handle); 2533 ret = SendSyncRequestWithUserBuffer64(system, message_buffer, message_buffer_size, session_handle);
2534 2534
2535 SetReg64(system, 0, Convert<uint64_t>(ret)); 2535 SetArg64(args, 0, Convert<uint64_t>(ret));
2536} 2536}
2537 2537
2538static void SvcWrap_SendAsyncRequestWithUserBuffer64(Core::System& system) { 2538static void SvcWrap_SendAsyncRequestWithUserBuffer64(Core::System& system, std::span<uint64_t, 8> args) {
2539 Result ret{}; 2539 Result ret{};
2540 2540
2541 Handle out_event_handle{}; 2541 Handle out_event_handle{};
@@ -2543,79 +2543,79 @@ static void SvcWrap_SendAsyncRequestWithUserBuffer64(Core::System& system) {
2543 uint64_t message_buffer_size{}; 2543 uint64_t message_buffer_size{};
2544 Handle session_handle{}; 2544 Handle session_handle{};
2545 2545
2546 message_buffer = Convert<uint64_t>(GetReg64(system, 1)); 2546 message_buffer = Convert<uint64_t>(GetArg64(args, 1));
2547 message_buffer_size = Convert<uint64_t>(GetReg64(system, 2)); 2547 message_buffer_size = Convert<uint64_t>(GetArg64(args, 2));
2548 session_handle = Convert<Handle>(GetReg64(system, 3)); 2548 session_handle = Convert<Handle>(GetArg64(args, 3));
2549 2549
2550 ret = SendAsyncRequestWithUserBuffer64(system, std::addressof(out_event_handle), message_buffer, message_buffer_size, session_handle); 2550 ret = SendAsyncRequestWithUserBuffer64(system, std::addressof(out_event_handle), message_buffer, message_buffer_size, session_handle);
2551 2551
2552 SetReg64(system, 0, Convert<uint64_t>(ret)); 2552 SetArg64(args, 0, Convert<uint64_t>(ret));
2553 SetReg64(system, 1, Convert<uint64_t>(out_event_handle)); 2553 SetArg64(args, 1, Convert<uint64_t>(out_event_handle));
2554} 2554}
2555 2555
2556static void SvcWrap_GetProcessId64(Core::System& system) { 2556static void SvcWrap_GetProcessId64(Core::System& system, std::span<uint64_t, 8> args) {
2557 Result ret{}; 2557 Result ret{};
2558 2558
2559 uint64_t out_process_id{}; 2559 uint64_t out_process_id{};
2560 Handle process_handle{}; 2560 Handle process_handle{};
2561 2561
2562 process_handle = Convert<Handle>(GetReg64(system, 1)); 2562 process_handle = Convert<Handle>(GetArg64(args, 1));
2563 2563
2564 ret = GetProcessId64(system, std::addressof(out_process_id), process_handle); 2564 ret = GetProcessId64(system, std::addressof(out_process_id), process_handle);
2565 2565
2566 SetReg64(system, 0, Convert<uint64_t>(ret)); 2566 SetArg64(args, 0, Convert<uint64_t>(ret));
2567 SetReg64(system, 1, Convert<uint64_t>(out_process_id)); 2567 SetArg64(args, 1, Convert<uint64_t>(out_process_id));
2568} 2568}
2569 2569
2570static void SvcWrap_GetThreadId64(Core::System& system) { 2570static void SvcWrap_GetThreadId64(Core::System& system, std::span<uint64_t, 8> args) {
2571 Result ret{}; 2571 Result ret{};
2572 2572
2573 uint64_t out_thread_id{}; 2573 uint64_t out_thread_id{};
2574 Handle thread_handle{}; 2574 Handle thread_handle{};
2575 2575
2576 thread_handle = Convert<Handle>(GetReg64(system, 1)); 2576 thread_handle = Convert<Handle>(GetArg64(args, 1));
2577 2577
2578 ret = GetThreadId64(system, std::addressof(out_thread_id), thread_handle); 2578 ret = GetThreadId64(system, std::addressof(out_thread_id), thread_handle);
2579 2579
2580 SetReg64(system, 0, Convert<uint64_t>(ret)); 2580 SetArg64(args, 0, Convert<uint64_t>(ret));
2581 SetReg64(system, 1, Convert<uint64_t>(out_thread_id)); 2581 SetArg64(args, 1, Convert<uint64_t>(out_thread_id));
2582} 2582}
2583 2583
2584static void SvcWrap_Break64(Core::System& system) { 2584static void SvcWrap_Break64(Core::System& system, std::span<uint64_t, 8> args) {
2585 BreakReason break_reason{}; 2585 BreakReason break_reason{};
2586 uint64_t arg{}; 2586 uint64_t arg{};
2587 uint64_t size{}; 2587 uint64_t size{};
2588 2588
2589 break_reason = Convert<BreakReason>(GetReg64(system, 0)); 2589 break_reason = Convert<BreakReason>(GetArg64(args, 0));
2590 arg = Convert<uint64_t>(GetReg64(system, 1)); 2590 arg = Convert<uint64_t>(GetArg64(args, 1));
2591 size = Convert<uint64_t>(GetReg64(system, 2)); 2591 size = Convert<uint64_t>(GetArg64(args, 2));
2592 2592
2593 Break64(system, break_reason, arg, size); 2593 Break64(system, break_reason, arg, size);
2594} 2594}
2595 2595
2596static void SvcWrap_OutputDebugString64(Core::System& system) { 2596static void SvcWrap_OutputDebugString64(Core::System& system, std::span<uint64_t, 8> args) {
2597 Result ret{}; 2597 Result ret{};
2598 2598
2599 uint64_t debug_str{}; 2599 uint64_t debug_str{};
2600 uint64_t len{}; 2600 uint64_t len{};
2601 2601
2602 debug_str = Convert<uint64_t>(GetReg64(system, 0)); 2602 debug_str = Convert<uint64_t>(GetArg64(args, 0));
2603 len = Convert<uint64_t>(GetReg64(system, 1)); 2603 len = Convert<uint64_t>(GetArg64(args, 1));
2604 2604
2605 ret = OutputDebugString64(system, debug_str, len); 2605 ret = OutputDebugString64(system, debug_str, len);
2606 2606
2607 SetReg64(system, 0, Convert<uint64_t>(ret)); 2607 SetArg64(args, 0, Convert<uint64_t>(ret));
2608} 2608}
2609 2609
2610static void SvcWrap_ReturnFromException64(Core::System& system) { 2610static void SvcWrap_ReturnFromException64(Core::System& system, std::span<uint64_t, 8> args) {
2611 Result result{}; 2611 Result result{};
2612 2612
2613 result = Convert<Result>(GetReg64(system, 0)); 2613 result = Convert<Result>(GetArg64(args, 0));
2614 2614
2615 ReturnFromException64(system, result); 2615 ReturnFromException64(system, result);
2616} 2616}
2617 2617
2618static void SvcWrap_GetInfo64(Core::System& system) { 2618static void SvcWrap_GetInfo64(Core::System& system, std::span<uint64_t, 8> args) {
2619 Result ret{}; 2619 Result ret{};
2620 2620
2621 uint64_t out{}; 2621 uint64_t out{};
@@ -2623,63 +2623,63 @@ static void SvcWrap_GetInfo64(Core::System& system) {
2623 Handle handle{}; 2623 Handle handle{};
2624 uint64_t info_subtype{}; 2624 uint64_t info_subtype{};
2625 2625
2626 info_type = Convert<InfoType>(GetReg64(system, 1)); 2626 info_type = Convert<InfoType>(GetArg64(args, 1));
2627 handle = Convert<Handle>(GetReg64(system, 2)); 2627 handle = Convert<Handle>(GetArg64(args, 2));
2628 info_subtype = Convert<uint64_t>(GetReg64(system, 3)); 2628 info_subtype = Convert<uint64_t>(GetArg64(args, 3));
2629 2629
2630 ret = GetInfo64(system, std::addressof(out), info_type, handle, info_subtype); 2630 ret = GetInfo64(system, std::addressof(out), info_type, handle, info_subtype);
2631 2631
2632 SetReg64(system, 0, Convert<uint64_t>(ret)); 2632 SetArg64(args, 0, Convert<uint64_t>(ret));
2633 SetReg64(system, 1, Convert<uint64_t>(out)); 2633 SetArg64(args, 1, Convert<uint64_t>(out));
2634} 2634}
2635 2635
2636static void SvcWrap_FlushEntireDataCache64(Core::System& system) { 2636static void SvcWrap_FlushEntireDataCache64(Core::System& system, std::span<uint64_t, 8> args) {
2637 FlushEntireDataCache64(system); 2637 FlushEntireDataCache64(system);
2638} 2638}
2639 2639
2640static void SvcWrap_FlushDataCache64(Core::System& system) { 2640static void SvcWrap_FlushDataCache64(Core::System& system, std::span<uint64_t, 8> args) {
2641 Result ret{}; 2641 Result ret{};
2642 2642
2643 uint64_t address{}; 2643 uint64_t address{};
2644 uint64_t size{}; 2644 uint64_t size{};
2645 2645
2646 address = Convert<uint64_t>(GetReg64(system, 0)); 2646 address = Convert<uint64_t>(GetArg64(args, 0));
2647 size = Convert<uint64_t>(GetReg64(system, 1)); 2647 size = Convert<uint64_t>(GetArg64(args, 1));
2648 2648
2649 ret = FlushDataCache64(system, address, size); 2649 ret = FlushDataCache64(system, address, size);
2650 2650
2651 SetReg64(system, 0, Convert<uint64_t>(ret)); 2651 SetArg64(args, 0, Convert<uint64_t>(ret));
2652} 2652}
2653 2653
2654static void SvcWrap_MapPhysicalMemory64(Core::System& system) { 2654static void SvcWrap_MapPhysicalMemory64(Core::System& system, std::span<uint64_t, 8> args) {
2655 Result ret{}; 2655 Result ret{};
2656 2656
2657 uint64_t address{}; 2657 uint64_t address{};
2658 uint64_t size{}; 2658 uint64_t size{};
2659 2659
2660 address = Convert<uint64_t>(GetReg64(system, 0)); 2660 address = Convert<uint64_t>(GetArg64(args, 0));
2661 size = Convert<uint64_t>(GetReg64(system, 1)); 2661 size = Convert<uint64_t>(GetArg64(args, 1));
2662 2662
2663 ret = MapPhysicalMemory64(system, address, size); 2663 ret = MapPhysicalMemory64(system, address, size);
2664 2664
2665 SetReg64(system, 0, Convert<uint64_t>(ret)); 2665 SetArg64(args, 0, Convert<uint64_t>(ret));
2666} 2666}
2667 2667
2668static void SvcWrap_UnmapPhysicalMemory64(Core::System& system) { 2668static void SvcWrap_UnmapPhysicalMemory64(Core::System& system, std::span<uint64_t, 8> args) {
2669 Result ret{}; 2669 Result ret{};
2670 2670
2671 uint64_t address{}; 2671 uint64_t address{};
2672 uint64_t size{}; 2672 uint64_t size{};
2673 2673
2674 address = Convert<uint64_t>(GetReg64(system, 0)); 2674 address = Convert<uint64_t>(GetArg64(args, 0));
2675 size = Convert<uint64_t>(GetReg64(system, 1)); 2675 size = Convert<uint64_t>(GetArg64(args, 1));
2676 2676
2677 ret = UnmapPhysicalMemory64(system, address, size); 2677 ret = UnmapPhysicalMemory64(system, address, size);
2678 2678
2679 SetReg64(system, 0, Convert<uint64_t>(ret)); 2679 SetArg64(args, 0, Convert<uint64_t>(ret));
2680} 2680}
2681 2681
2682static void SvcWrap_GetDebugFutureThreadInfo64(Core::System& system) { 2682static void SvcWrap_GetDebugFutureThreadInfo64(Core::System& system, std::span<uint64_t, 8> args) {
2683 Result ret{}; 2683 Result ret{};
2684 2684
2685 lp64::LastThreadContext out_context{}; 2685 lp64::LastThreadContext out_context{};
@@ -2687,21 +2687,21 @@ static void SvcWrap_GetDebugFutureThreadInfo64(Core::System& system) {
2687 Handle debug_handle{}; 2687 Handle debug_handle{};
2688 int64_t ns{}; 2688 int64_t ns{};
2689 2689
2690 debug_handle = Convert<Handle>(GetReg64(system, 2)); 2690 debug_handle = Convert<Handle>(GetArg64(args, 2));
2691 ns = Convert<int64_t>(GetReg64(system, 3)); 2691 ns = Convert<int64_t>(GetArg64(args, 3));
2692 2692
2693 ret = GetDebugFutureThreadInfo64(system, std::addressof(out_context), std::addressof(out_thread_id), debug_handle, ns); 2693 ret = GetDebugFutureThreadInfo64(system, std::addressof(out_context), std::addressof(out_thread_id), debug_handle, ns);
2694 2694
2695 SetReg64(system, 0, Convert<uint64_t>(ret)); 2695 SetArg64(args, 0, Convert<uint64_t>(ret));
2696 auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context); 2696 auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context);
2697 SetReg64(system, 1, out_context_scatter[0]); 2697 SetArg64(args, 1, out_context_scatter[0]);
2698 SetReg64(system, 2, out_context_scatter[1]); 2698 SetArg64(args, 2, out_context_scatter[1]);
2699 SetReg64(system, 3, out_context_scatter[2]); 2699 SetArg64(args, 3, out_context_scatter[2]);
2700 SetReg64(system, 4, out_context_scatter[3]); 2700 SetArg64(args, 4, out_context_scatter[3]);
2701 SetReg64(system, 5, Convert<uint64_t>(out_thread_id)); 2701 SetArg64(args, 5, Convert<uint64_t>(out_thread_id));
2702} 2702}
2703 2703
2704static void SvcWrap_GetLastThreadInfo64(Core::System& system) { 2704static void SvcWrap_GetLastThreadInfo64(Core::System& system, std::span<uint64_t, 8> args) {
2705 Result ret{}; 2705 Result ret{};
2706 2706
2707 lp64::LastThreadContext out_context{}; 2707 lp64::LastThreadContext out_context{};
@@ -2710,77 +2710,77 @@ static void SvcWrap_GetLastThreadInfo64(Core::System& system) {
2710 2710
2711 ret = GetLastThreadInfo64(system, std::addressof(out_context), std::addressof(out_tls_address), std::addressof(out_flags)); 2711 ret = GetLastThreadInfo64(system, std::addressof(out_context), std::addressof(out_tls_address), std::addressof(out_flags));
2712 2712
2713 SetReg64(system, 0, Convert<uint64_t>(ret)); 2713 SetArg64(args, 0, Convert<uint64_t>(ret));
2714 auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context); 2714 auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context);
2715 SetReg64(system, 1, out_context_scatter[0]); 2715 SetArg64(args, 1, out_context_scatter[0]);
2716 SetReg64(system, 2, out_context_scatter[1]); 2716 SetArg64(args, 2, out_context_scatter[1]);
2717 SetReg64(system, 3, out_context_scatter[2]); 2717 SetArg64(args, 3, out_context_scatter[2]);
2718 SetReg64(system, 4, out_context_scatter[3]); 2718 SetArg64(args, 4, out_context_scatter[3]);
2719 SetReg64(system, 5, Convert<uint64_t>(out_tls_address)); 2719 SetArg64(args, 5, Convert<uint64_t>(out_tls_address));
2720 SetReg64(system, 6, Convert<uint64_t>(out_flags)); 2720 SetArg64(args, 6, Convert<uint64_t>(out_flags));
2721} 2721}
2722 2722
2723static void SvcWrap_GetResourceLimitLimitValue64(Core::System& system) { 2723static void SvcWrap_GetResourceLimitLimitValue64(Core::System& system, std::span<uint64_t, 8> args) {
2724 Result ret{}; 2724 Result ret{};
2725 2725
2726 int64_t out_limit_value{}; 2726 int64_t out_limit_value{};
2727 Handle resource_limit_handle{}; 2727 Handle resource_limit_handle{};
2728 LimitableResource which{}; 2728 LimitableResource which{};
2729 2729
2730 resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); 2730 resource_limit_handle = Convert<Handle>(GetArg64(args, 1));
2731 which = Convert<LimitableResource>(GetReg64(system, 2)); 2731 which = Convert<LimitableResource>(GetArg64(args, 2));
2732 2732
2733 ret = GetResourceLimitLimitValue64(system, std::addressof(out_limit_value), resource_limit_handle, which); 2733 ret = GetResourceLimitLimitValue64(system, std::addressof(out_limit_value), resource_limit_handle, which);
2734 2734
2735 SetReg64(system, 0, Convert<uint64_t>(ret)); 2735 SetArg64(args, 0, Convert<uint64_t>(ret));
2736 SetReg64(system, 1, Convert<uint64_t>(out_limit_value)); 2736 SetArg64(args, 1, Convert<uint64_t>(out_limit_value));
2737} 2737}
2738 2738
2739static void SvcWrap_GetResourceLimitCurrentValue64(Core::System& system) { 2739static void SvcWrap_GetResourceLimitCurrentValue64(Core::System& system, std::span<uint64_t, 8> args) {
2740 Result ret{}; 2740 Result ret{};
2741 2741
2742 int64_t out_current_value{}; 2742 int64_t out_current_value{};
2743 Handle resource_limit_handle{}; 2743 Handle resource_limit_handle{};
2744 LimitableResource which{}; 2744 LimitableResource which{};
2745 2745
2746 resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); 2746 resource_limit_handle = Convert<Handle>(GetArg64(args, 1));
2747 which = Convert<LimitableResource>(GetReg64(system, 2)); 2747 which = Convert<LimitableResource>(GetArg64(args, 2));
2748 2748
2749 ret = GetResourceLimitCurrentValue64(system, std::addressof(out_current_value), resource_limit_handle, which); 2749 ret = GetResourceLimitCurrentValue64(system, std::addressof(out_current_value), resource_limit_handle, which);
2750 2750
2751 SetReg64(system, 0, Convert<uint64_t>(ret)); 2751 SetArg64(args, 0, Convert<uint64_t>(ret));
2752 SetReg64(system, 1, Convert<uint64_t>(out_current_value)); 2752 SetArg64(args, 1, Convert<uint64_t>(out_current_value));
2753} 2753}
2754 2754
2755static void SvcWrap_SetThreadActivity64(Core::System& system) { 2755static void SvcWrap_SetThreadActivity64(Core::System& system, std::span<uint64_t, 8> args) {
2756 Result ret{}; 2756 Result ret{};
2757 2757
2758 Handle thread_handle{}; 2758 Handle thread_handle{};
2759 ThreadActivity thread_activity{}; 2759 ThreadActivity thread_activity{};
2760 2760
2761 thread_handle = Convert<Handle>(GetReg64(system, 0)); 2761 thread_handle = Convert<Handle>(GetArg64(args, 0));
2762 thread_activity = Convert<ThreadActivity>(GetReg64(system, 1)); 2762 thread_activity = Convert<ThreadActivity>(GetArg64(args, 1));
2763 2763
2764 ret = SetThreadActivity64(system, thread_handle, thread_activity); 2764 ret = SetThreadActivity64(system, thread_handle, thread_activity);
2765 2765
2766 SetReg64(system, 0, Convert<uint64_t>(ret)); 2766 SetArg64(args, 0, Convert<uint64_t>(ret));
2767} 2767}
2768 2768
2769static void SvcWrap_GetThreadContext364(Core::System& system) { 2769static void SvcWrap_GetThreadContext364(Core::System& system, std::span<uint64_t, 8> args) {
2770 Result ret{}; 2770 Result ret{};
2771 2771
2772 uint64_t out_context{}; 2772 uint64_t out_context{};
2773 Handle thread_handle{}; 2773 Handle thread_handle{};
2774 2774
2775 out_context = Convert<uint64_t>(GetReg64(system, 0)); 2775 out_context = Convert<uint64_t>(GetArg64(args, 0));
2776 thread_handle = Convert<Handle>(GetReg64(system, 1)); 2776 thread_handle = Convert<Handle>(GetArg64(args, 1));
2777 2777
2778 ret = GetThreadContext364(system, out_context, thread_handle); 2778 ret = GetThreadContext364(system, out_context, thread_handle);
2779 2779
2780 SetReg64(system, 0, Convert<uint64_t>(ret)); 2780 SetArg64(args, 0, Convert<uint64_t>(ret));
2781} 2781}
2782 2782
2783static void SvcWrap_WaitForAddress64(Core::System& system) { 2783static void SvcWrap_WaitForAddress64(Core::System& system, std::span<uint64_t, 8> args) {
2784 Result ret{}; 2784 Result ret{};
2785 2785
2786 uint64_t address{}; 2786 uint64_t address{};
@@ -2788,17 +2788,17 @@ static void SvcWrap_WaitForAddress64(Core::System& system) {
2788 int32_t value{}; 2788 int32_t value{};
2789 int64_t timeout_ns{}; 2789 int64_t timeout_ns{};
2790 2790
2791 address = Convert<uint64_t>(GetReg64(system, 0)); 2791 address = Convert<uint64_t>(GetArg64(args, 0));
2792 arb_type = Convert<ArbitrationType>(GetReg64(system, 1)); 2792 arb_type = Convert<ArbitrationType>(GetArg64(args, 1));
2793 value = Convert<int32_t>(GetReg64(system, 2)); 2793 value = Convert<int32_t>(GetArg64(args, 2));
2794 timeout_ns = Convert<int64_t>(GetReg64(system, 3)); 2794 timeout_ns = Convert<int64_t>(GetArg64(args, 3));
2795 2795
2796 ret = WaitForAddress64(system, address, arb_type, value, timeout_ns); 2796 ret = WaitForAddress64(system, address, arb_type, value, timeout_ns);
2797 2797
2798 SetReg64(system, 0, Convert<uint64_t>(ret)); 2798 SetArg64(args, 0, Convert<uint64_t>(ret));
2799} 2799}
2800 2800
2801static void SvcWrap_SignalToAddress64(Core::System& system) { 2801static void SvcWrap_SignalToAddress64(Core::System& system, std::span<uint64_t, 8> args) {
2802 Result ret{}; 2802 Result ret{};
2803 2803
2804 uint64_t address{}; 2804 uint64_t address{};
@@ -2806,51 +2806,51 @@ static void SvcWrap_SignalToAddress64(Core::System& system) {
2806 int32_t value{}; 2806 int32_t value{};
2807 int32_t count{}; 2807 int32_t count{};
2808 2808
2809 address = Convert<uint64_t>(GetReg64(system, 0)); 2809 address = Convert<uint64_t>(GetArg64(args, 0));
2810 signal_type = Convert<SignalType>(GetReg64(system, 1)); 2810 signal_type = Convert<SignalType>(GetArg64(args, 1));
2811 value = Convert<int32_t>(GetReg64(system, 2)); 2811 value = Convert<int32_t>(GetArg64(args, 2));
2812 count = Convert<int32_t>(GetReg64(system, 3)); 2812 count = Convert<int32_t>(GetArg64(args, 3));
2813 2813
2814 ret = SignalToAddress64(system, address, signal_type, value, count); 2814 ret = SignalToAddress64(system, address, signal_type, value, count);
2815 2815
2816 SetReg64(system, 0, Convert<uint64_t>(ret)); 2816 SetArg64(args, 0, Convert<uint64_t>(ret));
2817} 2817}
2818 2818
2819static void SvcWrap_SynchronizePreemptionState64(Core::System& system) { 2819static void SvcWrap_SynchronizePreemptionState64(Core::System& system, std::span<uint64_t, 8> args) {
2820 SynchronizePreemptionState64(system); 2820 SynchronizePreemptionState64(system);
2821} 2821}
2822 2822
2823static void SvcWrap_GetResourceLimitPeakValue64(Core::System& system) { 2823static void SvcWrap_GetResourceLimitPeakValue64(Core::System& system, std::span<uint64_t, 8> args) {
2824 Result ret{}; 2824 Result ret{};
2825 2825
2826 int64_t out_peak_value{}; 2826 int64_t out_peak_value{};
2827 Handle resource_limit_handle{}; 2827 Handle resource_limit_handle{};
2828 LimitableResource which{}; 2828 LimitableResource which{};
2829 2829
2830 resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); 2830 resource_limit_handle = Convert<Handle>(GetArg64(args, 1));
2831 which = Convert<LimitableResource>(GetReg64(system, 2)); 2831 which = Convert<LimitableResource>(GetArg64(args, 2));
2832 2832
2833 ret = GetResourceLimitPeakValue64(system, std::addressof(out_peak_value), resource_limit_handle, which); 2833 ret = GetResourceLimitPeakValue64(system, std::addressof(out_peak_value), resource_limit_handle, which);
2834 2834
2835 SetReg64(system, 0, Convert<uint64_t>(ret)); 2835 SetArg64(args, 0, Convert<uint64_t>(ret));
2836 SetReg64(system, 1, Convert<uint64_t>(out_peak_value)); 2836 SetArg64(args, 1, Convert<uint64_t>(out_peak_value));
2837} 2837}
2838 2838
2839static void SvcWrap_CreateIoPool64(Core::System& system) { 2839static void SvcWrap_CreateIoPool64(Core::System& system, std::span<uint64_t, 8> args) {
2840 Result ret{}; 2840 Result ret{};
2841 2841
2842 Handle out_handle{}; 2842 Handle out_handle{};
2843 IoPoolType which{}; 2843 IoPoolType which{};
2844 2844
2845 which = Convert<IoPoolType>(GetReg64(system, 1)); 2845 which = Convert<IoPoolType>(GetArg64(args, 1));
2846 2846
2847 ret = CreateIoPool64(system, std::addressof(out_handle), which); 2847 ret = CreateIoPool64(system, std::addressof(out_handle), which);
2848 2848
2849 SetReg64(system, 0, Convert<uint64_t>(ret)); 2849 SetArg64(args, 0, Convert<uint64_t>(ret));
2850 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 2850 SetArg64(args, 1, Convert<uint64_t>(out_handle));
2851} 2851}
2852 2852
2853static void SvcWrap_CreateIoRegion64(Core::System& system) { 2853static void SvcWrap_CreateIoRegion64(Core::System& system, std::span<uint64_t, 8> args) {
2854 Result ret{}; 2854 Result ret{};
2855 2855
2856 Handle out_handle{}; 2856 Handle out_handle{};
@@ -2860,41 +2860,41 @@ static void SvcWrap_CreateIoRegion64(Core::System& system) {
2860 MemoryMapping mapping{}; 2860 MemoryMapping mapping{};
2861 MemoryPermission perm{}; 2861 MemoryPermission perm{};
2862 2862
2863 io_pool = Convert<Handle>(GetReg64(system, 1)); 2863 io_pool = Convert<Handle>(GetArg64(args, 1));
2864 physical_address = Convert<uint64_t>(GetReg64(system, 2)); 2864 physical_address = Convert<uint64_t>(GetArg64(args, 2));
2865 size = Convert<uint64_t>(GetReg64(system, 3)); 2865 size = Convert<uint64_t>(GetArg64(args, 3));
2866 mapping = Convert<MemoryMapping>(GetReg64(system, 4)); 2866 mapping = Convert<MemoryMapping>(GetArg64(args, 4));
2867 perm = Convert<MemoryPermission>(GetReg64(system, 5)); 2867 perm = Convert<MemoryPermission>(GetArg64(args, 5));
2868 2868
2869 ret = CreateIoRegion64(system, std::addressof(out_handle), io_pool, physical_address, size, mapping, perm); 2869 ret = CreateIoRegion64(system, std::addressof(out_handle), io_pool, physical_address, size, mapping, perm);
2870 2870
2871 SetReg64(system, 0, Convert<uint64_t>(ret)); 2871 SetArg64(args, 0, Convert<uint64_t>(ret));
2872 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 2872 SetArg64(args, 1, Convert<uint64_t>(out_handle));
2873} 2873}
2874 2874
2875static void SvcWrap_KernelDebug64(Core::System& system) { 2875static void SvcWrap_KernelDebug64(Core::System& system, std::span<uint64_t, 8> args) {
2876 KernelDebugType kern_debug_type{}; 2876 KernelDebugType kern_debug_type{};
2877 uint64_t arg0{}; 2877 uint64_t arg0{};
2878 uint64_t arg1{}; 2878 uint64_t arg1{};
2879 uint64_t arg2{}; 2879 uint64_t arg2{};
2880 2880
2881 kern_debug_type = Convert<KernelDebugType>(GetReg64(system, 0)); 2881 kern_debug_type = Convert<KernelDebugType>(GetArg64(args, 0));
2882 arg0 = Convert<uint64_t>(GetReg64(system, 1)); 2882 arg0 = Convert<uint64_t>(GetArg64(args, 1));
2883 arg1 = Convert<uint64_t>(GetReg64(system, 2)); 2883 arg1 = Convert<uint64_t>(GetArg64(args, 2));
2884 arg2 = Convert<uint64_t>(GetReg64(system, 3)); 2884 arg2 = Convert<uint64_t>(GetArg64(args, 3));
2885 2885
2886 KernelDebug64(system, kern_debug_type, arg0, arg1, arg2); 2886 KernelDebug64(system, kern_debug_type, arg0, arg1, arg2);
2887} 2887}
2888 2888
2889static void SvcWrap_ChangeKernelTraceState64(Core::System& system) { 2889static void SvcWrap_ChangeKernelTraceState64(Core::System& system, std::span<uint64_t, 8> args) {
2890 KernelTraceState kern_trace_state{}; 2890 KernelTraceState kern_trace_state{};
2891 2891
2892 kern_trace_state = Convert<KernelTraceState>(GetReg64(system, 0)); 2892 kern_trace_state = Convert<KernelTraceState>(GetArg64(args, 0));
2893 2893
2894 ChangeKernelTraceState64(system, kern_trace_state); 2894 ChangeKernelTraceState64(system, kern_trace_state);
2895} 2895}
2896 2896
2897static void SvcWrap_CreateSession64(Core::System& system) { 2897static void SvcWrap_CreateSession64(Core::System& system, std::span<uint64_t, 8> args) {
2898 Result ret{}; 2898 Result ret{};
2899 2899
2900 Handle out_server_session_handle{}; 2900 Handle out_server_session_handle{};
@@ -2902,31 +2902,31 @@ static void SvcWrap_CreateSession64(Core::System& system) {
2902 bool is_light{}; 2902 bool is_light{};
2903 uint64_t name{}; 2903 uint64_t name{};
2904 2904
2905 is_light = Convert<bool>(GetReg64(system, 2)); 2905 is_light = Convert<bool>(GetArg64(args, 2));
2906 name = Convert<uint64_t>(GetReg64(system, 3)); 2906 name = Convert<uint64_t>(GetArg64(args, 3));
2907 2907
2908 ret = CreateSession64(system, std::addressof(out_server_session_handle), std::addressof(out_client_session_handle), is_light, name); 2908 ret = CreateSession64(system, std::addressof(out_server_session_handle), std::addressof(out_client_session_handle), is_light, name);
2909 2909
2910 SetReg64(system, 0, Convert<uint64_t>(ret)); 2910 SetArg64(args, 0, Convert<uint64_t>(ret));
2911 SetReg64(system, 1, Convert<uint64_t>(out_server_session_handle)); 2911 SetArg64(args, 1, Convert<uint64_t>(out_server_session_handle));
2912 SetReg64(system, 2, Convert<uint64_t>(out_client_session_handle)); 2912 SetArg64(args, 2, Convert<uint64_t>(out_client_session_handle));
2913} 2913}
2914 2914
2915static void SvcWrap_AcceptSession64(Core::System& system) { 2915static void SvcWrap_AcceptSession64(Core::System& system, std::span<uint64_t, 8> args) {
2916 Result ret{}; 2916 Result ret{};
2917 2917
2918 Handle out_handle{}; 2918 Handle out_handle{};
2919 Handle port{}; 2919 Handle port{};
2920 2920
2921 port = Convert<Handle>(GetReg64(system, 1)); 2921 port = Convert<Handle>(GetArg64(args, 1));
2922 2922
2923 ret = AcceptSession64(system, std::addressof(out_handle), port); 2923 ret = AcceptSession64(system, std::addressof(out_handle), port);
2924 2924
2925 SetReg64(system, 0, Convert<uint64_t>(ret)); 2925 SetArg64(args, 0, Convert<uint64_t>(ret));
2926 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 2926 SetArg64(args, 1, Convert<uint64_t>(out_handle));
2927} 2927}
2928 2928
2929static void SvcWrap_ReplyAndReceive64(Core::System& system) { 2929static void SvcWrap_ReplyAndReceive64(Core::System& system, std::span<uint64_t, 8> args) {
2930 Result ret{}; 2930 Result ret{};
2931 2931
2932 int32_t out_index{}; 2932 int32_t out_index{};
@@ -2935,18 +2935,18 @@ static void SvcWrap_ReplyAndReceive64(Core::System& system) {
2935 Handle reply_target{}; 2935 Handle reply_target{};
2936 int64_t timeout_ns{}; 2936 int64_t timeout_ns{};
2937 2937
2938 handles = Convert<uint64_t>(GetReg64(system, 1)); 2938 handles = Convert<uint64_t>(GetArg64(args, 1));
2939 num_handles = Convert<int32_t>(GetReg64(system, 2)); 2939 num_handles = Convert<int32_t>(GetArg64(args, 2));
2940 reply_target = Convert<Handle>(GetReg64(system, 3)); 2940 reply_target = Convert<Handle>(GetArg64(args, 3));
2941 timeout_ns = Convert<int64_t>(GetReg64(system, 4)); 2941 timeout_ns = Convert<int64_t>(GetArg64(args, 4));
2942 2942
2943 ret = ReplyAndReceive64(system, std::addressof(out_index), handles, num_handles, reply_target, timeout_ns); 2943 ret = ReplyAndReceive64(system, std::addressof(out_index), handles, num_handles, reply_target, timeout_ns);
2944 2944
2945 SetReg64(system, 0, Convert<uint64_t>(ret)); 2945 SetArg64(args, 0, Convert<uint64_t>(ret));
2946 SetReg64(system, 1, Convert<uint64_t>(out_index)); 2946 SetArg64(args, 1, Convert<uint64_t>(out_index));
2947} 2947}
2948 2948
2949static void SvcWrap_ReplyAndReceiveWithUserBuffer64(Core::System& system) { 2949static void SvcWrap_ReplyAndReceiveWithUserBuffer64(Core::System& system, std::span<uint64_t, 8> args) {
2950 Result ret{}; 2950 Result ret{};
2951 2951
2952 int32_t out_index{}; 2952 int32_t out_index{};
@@ -2957,20 +2957,20 @@ static void SvcWrap_ReplyAndReceiveWithUserBuffer64(Core::System& system) {
2957 Handle reply_target{}; 2957 Handle reply_target{};
2958 int64_t timeout_ns{}; 2958 int64_t timeout_ns{};
2959 2959
2960 message_buffer = Convert<uint64_t>(GetReg64(system, 1)); 2960 message_buffer = Convert<uint64_t>(GetArg64(args, 1));
2961 message_buffer_size = Convert<uint64_t>(GetReg64(system, 2)); 2961 message_buffer_size = Convert<uint64_t>(GetArg64(args, 2));
2962 handles = Convert<uint64_t>(GetReg64(system, 3)); 2962 handles = Convert<uint64_t>(GetArg64(args, 3));
2963 num_handles = Convert<int32_t>(GetReg64(system, 4)); 2963 num_handles = Convert<int32_t>(GetArg64(args, 4));
2964 reply_target = Convert<Handle>(GetReg64(system, 5)); 2964 reply_target = Convert<Handle>(GetArg64(args, 5));
2965 timeout_ns = Convert<int64_t>(GetReg64(system, 6)); 2965 timeout_ns = Convert<int64_t>(GetArg64(args, 6));
2966 2966
2967 ret = ReplyAndReceiveWithUserBuffer64(system, std::addressof(out_index), message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns); 2967 ret = ReplyAndReceiveWithUserBuffer64(system, std::addressof(out_index), message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns);
2968 2968
2969 SetReg64(system, 0, Convert<uint64_t>(ret)); 2969 SetArg64(args, 0, Convert<uint64_t>(ret));
2970 SetReg64(system, 1, Convert<uint64_t>(out_index)); 2970 SetArg64(args, 1, Convert<uint64_t>(out_index));
2971} 2971}
2972 2972
2973static void SvcWrap_CreateEvent64(Core::System& system) { 2973static void SvcWrap_CreateEvent64(Core::System& system, std::span<uint64_t, 8> args) {
2974 Result ret{}; 2974 Result ret{};
2975 2975
2976 Handle out_write_handle{}; 2976 Handle out_write_handle{};
@@ -2978,12 +2978,12 @@ static void SvcWrap_CreateEvent64(Core::System& system) {
2978 2978
2979 ret = CreateEvent64(system, std::addressof(out_write_handle), std::addressof(out_read_handle)); 2979 ret = CreateEvent64(system, std::addressof(out_write_handle), std::addressof(out_read_handle));
2980 2980
2981 SetReg64(system, 0, Convert<uint64_t>(ret)); 2981 SetArg64(args, 0, Convert<uint64_t>(ret));
2982 SetReg64(system, 1, Convert<uint64_t>(out_write_handle)); 2982 SetArg64(args, 1, Convert<uint64_t>(out_write_handle));
2983 SetReg64(system, 2, Convert<uint64_t>(out_read_handle)); 2983 SetArg64(args, 2, Convert<uint64_t>(out_read_handle));
2984} 2984}
2985 2985
2986static void SvcWrap_MapIoRegion64(Core::System& system) { 2986static void SvcWrap_MapIoRegion64(Core::System& system, std::span<uint64_t, 8> args) {
2987 Result ret{}; 2987 Result ret{};
2988 2988
2989 Handle io_region{}; 2989 Handle io_region{};
@@ -2991,89 +2991,89 @@ static void SvcWrap_MapIoRegion64(Core::System& system) {
2991 uint64_t size{}; 2991 uint64_t size{};
2992 MemoryPermission perm{}; 2992 MemoryPermission perm{};
2993 2993
2994 io_region = Convert<Handle>(GetReg64(system, 0)); 2994 io_region = Convert<Handle>(GetArg64(args, 0));
2995 address = Convert<uint64_t>(GetReg64(system, 1)); 2995 address = Convert<uint64_t>(GetArg64(args, 1));
2996 size = Convert<uint64_t>(GetReg64(system, 2)); 2996 size = Convert<uint64_t>(GetArg64(args, 2));
2997 perm = Convert<MemoryPermission>(GetReg64(system, 3)); 2997 perm = Convert<MemoryPermission>(GetArg64(args, 3));
2998 2998
2999 ret = MapIoRegion64(system, io_region, address, size, perm); 2999 ret = MapIoRegion64(system, io_region, address, size, perm);
3000 3000
3001 SetReg64(system, 0, Convert<uint64_t>(ret)); 3001 SetArg64(args, 0, Convert<uint64_t>(ret));
3002} 3002}
3003 3003
3004static void SvcWrap_UnmapIoRegion64(Core::System& system) { 3004static void SvcWrap_UnmapIoRegion64(Core::System& system, std::span<uint64_t, 8> args) {
3005 Result ret{}; 3005 Result ret{};
3006 3006
3007 Handle io_region{}; 3007 Handle io_region{};
3008 uint64_t address{}; 3008 uint64_t address{};
3009 uint64_t size{}; 3009 uint64_t size{};
3010 3010
3011 io_region = Convert<Handle>(GetReg64(system, 0)); 3011 io_region = Convert<Handle>(GetArg64(args, 0));
3012 address = Convert<uint64_t>(GetReg64(system, 1)); 3012 address = Convert<uint64_t>(GetArg64(args, 1));
3013 size = Convert<uint64_t>(GetReg64(system, 2)); 3013 size = Convert<uint64_t>(GetArg64(args, 2));
3014 3014
3015 ret = UnmapIoRegion64(system, io_region, address, size); 3015 ret = UnmapIoRegion64(system, io_region, address, size);
3016 3016
3017 SetReg64(system, 0, Convert<uint64_t>(ret)); 3017 SetArg64(args, 0, Convert<uint64_t>(ret));
3018} 3018}
3019 3019
3020static void SvcWrap_MapPhysicalMemoryUnsafe64(Core::System& system) { 3020static void SvcWrap_MapPhysicalMemoryUnsafe64(Core::System& system, std::span<uint64_t, 8> args) {
3021 Result ret{}; 3021 Result ret{};
3022 3022
3023 uint64_t address{}; 3023 uint64_t address{};
3024 uint64_t size{}; 3024 uint64_t size{};
3025 3025
3026 address = Convert<uint64_t>(GetReg64(system, 0)); 3026 address = Convert<uint64_t>(GetArg64(args, 0));
3027 size = Convert<uint64_t>(GetReg64(system, 1)); 3027 size = Convert<uint64_t>(GetArg64(args, 1));
3028 3028
3029 ret = MapPhysicalMemoryUnsafe64(system, address, size); 3029 ret = MapPhysicalMemoryUnsafe64(system, address, size);
3030 3030
3031 SetReg64(system, 0, Convert<uint64_t>(ret)); 3031 SetArg64(args, 0, Convert<uint64_t>(ret));
3032} 3032}
3033 3033
3034static void SvcWrap_UnmapPhysicalMemoryUnsafe64(Core::System& system) { 3034static void SvcWrap_UnmapPhysicalMemoryUnsafe64(Core::System& system, std::span<uint64_t, 8> args) {
3035 Result ret{}; 3035 Result ret{};
3036 3036
3037 uint64_t address{}; 3037 uint64_t address{};
3038 uint64_t size{}; 3038 uint64_t size{};
3039 3039
3040 address = Convert<uint64_t>(GetReg64(system, 0)); 3040 address = Convert<uint64_t>(GetArg64(args, 0));
3041 size = Convert<uint64_t>(GetReg64(system, 1)); 3041 size = Convert<uint64_t>(GetArg64(args, 1));
3042 3042
3043 ret = UnmapPhysicalMemoryUnsafe64(system, address, size); 3043 ret = UnmapPhysicalMemoryUnsafe64(system, address, size);
3044 3044
3045 SetReg64(system, 0, Convert<uint64_t>(ret)); 3045 SetArg64(args, 0, Convert<uint64_t>(ret));
3046} 3046}
3047 3047
3048static void SvcWrap_SetUnsafeLimit64(Core::System& system) { 3048static void SvcWrap_SetUnsafeLimit64(Core::System& system, std::span<uint64_t, 8> args) {
3049 Result ret{}; 3049 Result ret{};
3050 3050
3051 uint64_t limit{}; 3051 uint64_t limit{};
3052 3052
3053 limit = Convert<uint64_t>(GetReg64(system, 0)); 3053 limit = Convert<uint64_t>(GetArg64(args, 0));
3054 3054
3055 ret = SetUnsafeLimit64(system, limit); 3055 ret = SetUnsafeLimit64(system, limit);
3056 3056
3057 SetReg64(system, 0, Convert<uint64_t>(ret)); 3057 SetArg64(args, 0, Convert<uint64_t>(ret));
3058} 3058}
3059 3059
3060static void SvcWrap_CreateCodeMemory64(Core::System& system) { 3060static void SvcWrap_CreateCodeMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3061 Result ret{}; 3061 Result ret{};
3062 3062
3063 Handle out_handle{}; 3063 Handle out_handle{};
3064 uint64_t address{}; 3064 uint64_t address{};
3065 uint64_t size{}; 3065 uint64_t size{};
3066 3066
3067 address = Convert<uint64_t>(GetReg64(system, 1)); 3067 address = Convert<uint64_t>(GetArg64(args, 1));
3068 size = Convert<uint64_t>(GetReg64(system, 2)); 3068 size = Convert<uint64_t>(GetArg64(args, 2));
3069 3069
3070 ret = CreateCodeMemory64(system, std::addressof(out_handle), address, size); 3070 ret = CreateCodeMemory64(system, std::addressof(out_handle), address, size);
3071 3071
3072 SetReg64(system, 0, Convert<uint64_t>(ret)); 3072 SetArg64(args, 0, Convert<uint64_t>(ret));
3073 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 3073 SetArg64(args, 1, Convert<uint64_t>(out_handle));
3074} 3074}
3075 3075
3076static void SvcWrap_ControlCodeMemory64(Core::System& system) { 3076static void SvcWrap_ControlCodeMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3077 Result ret{}; 3077 Result ret{};
3078 3078
3079 Handle code_memory_handle{}; 3079 Handle code_memory_handle{};
@@ -3082,22 +3082,22 @@ static void SvcWrap_ControlCodeMemory64(Core::System& system) {
3082 uint64_t size{}; 3082 uint64_t size{};
3083 MemoryPermission perm{}; 3083 MemoryPermission perm{};
3084 3084
3085 code_memory_handle = Convert<Handle>(GetReg64(system, 0)); 3085 code_memory_handle = Convert<Handle>(GetArg64(args, 0));
3086 operation = Convert<CodeMemoryOperation>(GetReg64(system, 1)); 3086 operation = Convert<CodeMemoryOperation>(GetArg64(args, 1));
3087 address = Convert<uint64_t>(GetReg64(system, 2)); 3087 address = Convert<uint64_t>(GetArg64(args, 2));
3088 size = Convert<uint64_t>(GetReg64(system, 3)); 3088 size = Convert<uint64_t>(GetArg64(args, 3));
3089 perm = Convert<MemoryPermission>(GetReg64(system, 4)); 3089 perm = Convert<MemoryPermission>(GetArg64(args, 4));
3090 3090
3091 ret = ControlCodeMemory64(system, code_memory_handle, operation, address, size, perm); 3091 ret = ControlCodeMemory64(system, code_memory_handle, operation, address, size, perm);
3092 3092
3093 SetReg64(system, 0, Convert<uint64_t>(ret)); 3093 SetArg64(args, 0, Convert<uint64_t>(ret));
3094} 3094}
3095 3095
3096static void SvcWrap_SleepSystem64(Core::System& system) { 3096static void SvcWrap_SleepSystem64(Core::System& system, std::span<uint64_t, 8> args) {
3097 SleepSystem64(system); 3097 SleepSystem64(system);
3098} 3098}
3099 3099
3100static void SvcWrap_ReadWriteRegister64(Core::System& system) { 3100static void SvcWrap_ReadWriteRegister64(Core::System& system, std::span<uint64_t, 8> args) {
3101 Result ret{}; 3101 Result ret{};
3102 3102
3103 uint32_t out_value{}; 3103 uint32_t out_value{};
@@ -3105,31 +3105,31 @@ static void SvcWrap_ReadWriteRegister64(Core::System& system) {
3105 uint32_t mask{}; 3105 uint32_t mask{};
3106 uint32_t value{}; 3106 uint32_t value{};
3107 3107
3108 address = Convert<uint64_t>(GetReg64(system, 1)); 3108 address = Convert<uint64_t>(GetArg64(args, 1));
3109 mask = Convert<uint32_t>(GetReg64(system, 2)); 3109 mask = Convert<uint32_t>(GetArg64(args, 2));
3110 value = Convert<uint32_t>(GetReg64(system, 3)); 3110 value = Convert<uint32_t>(GetArg64(args, 3));
3111 3111
3112 ret = ReadWriteRegister64(system, std::addressof(out_value), address, mask, value); 3112 ret = ReadWriteRegister64(system, std::addressof(out_value), address, mask, value);
3113 3113
3114 SetReg64(system, 0, Convert<uint64_t>(ret)); 3114 SetArg64(args, 0, Convert<uint64_t>(ret));
3115 SetReg64(system, 1, Convert<uint64_t>(out_value)); 3115 SetArg64(args, 1, Convert<uint64_t>(out_value));
3116} 3116}
3117 3117
3118static void SvcWrap_SetProcessActivity64(Core::System& system) { 3118static void SvcWrap_SetProcessActivity64(Core::System& system, std::span<uint64_t, 8> args) {
3119 Result ret{}; 3119 Result ret{};
3120 3120
3121 Handle process_handle{}; 3121 Handle process_handle{};
3122 ProcessActivity process_activity{}; 3122 ProcessActivity process_activity{};
3123 3123
3124 process_handle = Convert<Handle>(GetReg64(system, 0)); 3124 process_handle = Convert<Handle>(GetArg64(args, 0));
3125 process_activity = Convert<ProcessActivity>(GetReg64(system, 1)); 3125 process_activity = Convert<ProcessActivity>(GetArg64(args, 1));
3126 3126
3127 ret = SetProcessActivity64(system, process_handle, process_activity); 3127 ret = SetProcessActivity64(system, process_handle, process_activity);
3128 3128
3129 SetReg64(system, 0, Convert<uint64_t>(ret)); 3129 SetArg64(args, 0, Convert<uint64_t>(ret));
3130} 3130}
3131 3131
3132static void SvcWrap_CreateSharedMemory64(Core::System& system) { 3132static void SvcWrap_CreateSharedMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3133 Result ret{}; 3133 Result ret{};
3134 3134
3135 Handle out_handle{}; 3135 Handle out_handle{};
@@ -3137,17 +3137,17 @@ static void SvcWrap_CreateSharedMemory64(Core::System& system) {
3137 MemoryPermission owner_perm{}; 3137 MemoryPermission owner_perm{};
3138 MemoryPermission remote_perm{}; 3138 MemoryPermission remote_perm{};
3139 3139
3140 size = Convert<uint64_t>(GetReg64(system, 1)); 3140 size = Convert<uint64_t>(GetArg64(args, 1));
3141 owner_perm = Convert<MemoryPermission>(GetReg64(system, 2)); 3141 owner_perm = Convert<MemoryPermission>(GetArg64(args, 2));
3142 remote_perm = Convert<MemoryPermission>(GetReg64(system, 3)); 3142 remote_perm = Convert<MemoryPermission>(GetArg64(args, 3));
3143 3143
3144 ret = CreateSharedMemory64(system, std::addressof(out_handle), size, owner_perm, remote_perm); 3144 ret = CreateSharedMemory64(system, std::addressof(out_handle), size, owner_perm, remote_perm);
3145 3145
3146 SetReg64(system, 0, Convert<uint64_t>(ret)); 3146 SetArg64(args, 0, Convert<uint64_t>(ret));
3147 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 3147 SetArg64(args, 1, Convert<uint64_t>(out_handle));
3148} 3148}
3149 3149
3150static void SvcWrap_MapTransferMemory64(Core::System& system) { 3150static void SvcWrap_MapTransferMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3151 Result ret{}; 3151 Result ret{};
3152 3152
3153 Handle trmem_handle{}; 3153 Handle trmem_handle{};
@@ -3155,66 +3155,66 @@ static void SvcWrap_MapTransferMemory64(Core::System& system) {
3155 uint64_t size{}; 3155 uint64_t size{};
3156 MemoryPermission owner_perm{}; 3156 MemoryPermission owner_perm{};
3157 3157
3158 trmem_handle = Convert<Handle>(GetReg64(system, 0)); 3158 trmem_handle = Convert<Handle>(GetArg64(args, 0));
3159 address = Convert<uint64_t>(GetReg64(system, 1)); 3159 address = Convert<uint64_t>(GetArg64(args, 1));
3160 size = Convert<uint64_t>(GetReg64(system, 2)); 3160 size = Convert<uint64_t>(GetArg64(args, 2));
3161 owner_perm = Convert<MemoryPermission>(GetReg64(system, 3)); 3161 owner_perm = Convert<MemoryPermission>(GetArg64(args, 3));
3162 3162
3163 ret = MapTransferMemory64(system, trmem_handle, address, size, owner_perm); 3163 ret = MapTransferMemory64(system, trmem_handle, address, size, owner_perm);
3164 3164
3165 SetReg64(system, 0, Convert<uint64_t>(ret)); 3165 SetArg64(args, 0, Convert<uint64_t>(ret));
3166} 3166}
3167 3167
3168static void SvcWrap_UnmapTransferMemory64(Core::System& system) { 3168static void SvcWrap_UnmapTransferMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3169 Result ret{}; 3169 Result ret{};
3170 3170
3171 Handle trmem_handle{}; 3171 Handle trmem_handle{};
3172 uint64_t address{}; 3172 uint64_t address{};
3173 uint64_t size{}; 3173 uint64_t size{};
3174 3174
3175 trmem_handle = Convert<Handle>(GetReg64(system, 0)); 3175 trmem_handle = Convert<Handle>(GetArg64(args, 0));
3176 address = Convert<uint64_t>(GetReg64(system, 1)); 3176 address = Convert<uint64_t>(GetArg64(args, 1));
3177 size = Convert<uint64_t>(GetReg64(system, 2)); 3177 size = Convert<uint64_t>(GetArg64(args, 2));
3178 3178
3179 ret = UnmapTransferMemory64(system, trmem_handle, address, size); 3179 ret = UnmapTransferMemory64(system, trmem_handle, address, size);
3180 3180
3181 SetReg64(system, 0, Convert<uint64_t>(ret)); 3181 SetArg64(args, 0, Convert<uint64_t>(ret));
3182} 3182}
3183 3183
3184static void SvcWrap_CreateInterruptEvent64(Core::System& system) { 3184static void SvcWrap_CreateInterruptEvent64(Core::System& system, std::span<uint64_t, 8> args) {
3185 Result ret{}; 3185 Result ret{};
3186 3186
3187 Handle out_read_handle{}; 3187 Handle out_read_handle{};
3188 int32_t interrupt_id{}; 3188 int32_t interrupt_id{};
3189 InterruptType interrupt_type{}; 3189 InterruptType interrupt_type{};
3190 3190
3191 interrupt_id = Convert<int32_t>(GetReg64(system, 1)); 3191 interrupt_id = Convert<int32_t>(GetArg64(args, 1));
3192 interrupt_type = Convert<InterruptType>(GetReg64(system, 2)); 3192 interrupt_type = Convert<InterruptType>(GetArg64(args, 2));
3193 3193
3194 ret = CreateInterruptEvent64(system, std::addressof(out_read_handle), interrupt_id, interrupt_type); 3194 ret = CreateInterruptEvent64(system, std::addressof(out_read_handle), interrupt_id, interrupt_type);
3195 3195
3196 SetReg64(system, 0, Convert<uint64_t>(ret)); 3196 SetArg64(args, 0, Convert<uint64_t>(ret));
3197 SetReg64(system, 1, Convert<uint64_t>(out_read_handle)); 3197 SetArg64(args, 1, Convert<uint64_t>(out_read_handle));
3198} 3198}
3199 3199
3200static void SvcWrap_QueryPhysicalAddress64(Core::System& system) { 3200static void SvcWrap_QueryPhysicalAddress64(Core::System& system, std::span<uint64_t, 8> args) {
3201 Result ret{}; 3201 Result ret{};
3202 3202
3203 lp64::PhysicalMemoryInfo out_info{}; 3203 lp64::PhysicalMemoryInfo out_info{};
3204 uint64_t address{}; 3204 uint64_t address{};
3205 3205
3206 address = Convert<uint64_t>(GetReg64(system, 1)); 3206 address = Convert<uint64_t>(GetArg64(args, 1));
3207 3207
3208 ret = QueryPhysicalAddress64(system, std::addressof(out_info), address); 3208 ret = QueryPhysicalAddress64(system, std::addressof(out_info), address);
3209 3209
3210 SetReg64(system, 0, Convert<uint64_t>(ret)); 3210 SetArg64(args, 0, Convert<uint64_t>(ret));
3211 auto out_info_scatter = Convert<std::array<uint64_t, 3>>(out_info); 3211 auto out_info_scatter = Convert<std::array<uint64_t, 3>>(out_info);
3212 SetReg64(system, 1, out_info_scatter[0]); 3212 SetArg64(args, 1, out_info_scatter[0]);
3213 SetReg64(system, 2, out_info_scatter[1]); 3213 SetArg64(args, 2, out_info_scatter[1]);
3214 SetReg64(system, 3, out_info_scatter[2]); 3214 SetArg64(args, 3, out_info_scatter[2]);
3215} 3215}
3216 3216
3217static void SvcWrap_QueryIoMapping64(Core::System& system) { 3217static void SvcWrap_QueryIoMapping64(Core::System& system, std::span<uint64_t, 8> args) {
3218 Result ret{}; 3218 Result ret{};
3219 3219
3220 uint64_t out_address{}; 3220 uint64_t out_address{};
@@ -3222,61 +3222,61 @@ static void SvcWrap_QueryIoMapping64(Core::System& system) {
3222 uint64_t physical_address{}; 3222 uint64_t physical_address{};
3223 uint64_t size{}; 3223 uint64_t size{};
3224 3224
3225 physical_address = Convert<uint64_t>(GetReg64(system, 2)); 3225 physical_address = Convert<uint64_t>(GetArg64(args, 2));
3226 size = Convert<uint64_t>(GetReg64(system, 3)); 3226 size = Convert<uint64_t>(GetArg64(args, 3));
3227 3227
3228 ret = QueryIoMapping64(system, std::addressof(out_address), std::addressof(out_size), physical_address, size); 3228 ret = QueryIoMapping64(system, std::addressof(out_address), std::addressof(out_size), physical_address, size);
3229 3229
3230 SetReg64(system, 0, Convert<uint64_t>(ret)); 3230 SetArg64(args, 0, Convert<uint64_t>(ret));
3231 SetReg64(system, 1, Convert<uint64_t>(out_address)); 3231 SetArg64(args, 1, Convert<uint64_t>(out_address));
3232 SetReg64(system, 2, Convert<uint64_t>(out_size)); 3232 SetArg64(args, 2, Convert<uint64_t>(out_size));
3233} 3233}
3234 3234
3235static void SvcWrap_CreateDeviceAddressSpace64(Core::System& system) { 3235static void SvcWrap_CreateDeviceAddressSpace64(Core::System& system, std::span<uint64_t, 8> args) {
3236 Result ret{}; 3236 Result ret{};
3237 3237
3238 Handle out_handle{}; 3238 Handle out_handle{};
3239 uint64_t das_address{}; 3239 uint64_t das_address{};
3240 uint64_t das_size{}; 3240 uint64_t das_size{};
3241 3241
3242 das_address = Convert<uint64_t>(GetReg64(system, 1)); 3242 das_address = Convert<uint64_t>(GetArg64(args, 1));
3243 das_size = Convert<uint64_t>(GetReg64(system, 2)); 3243 das_size = Convert<uint64_t>(GetArg64(args, 2));
3244 3244
3245 ret = CreateDeviceAddressSpace64(system, std::addressof(out_handle), das_address, das_size); 3245 ret = CreateDeviceAddressSpace64(system, std::addressof(out_handle), das_address, das_size);
3246 3246
3247 SetReg64(system, 0, Convert<uint64_t>(ret)); 3247 SetArg64(args, 0, Convert<uint64_t>(ret));
3248 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 3248 SetArg64(args, 1, Convert<uint64_t>(out_handle));
3249} 3249}
3250 3250
3251static void SvcWrap_AttachDeviceAddressSpace64(Core::System& system) { 3251static void SvcWrap_AttachDeviceAddressSpace64(Core::System& system, std::span<uint64_t, 8> args) {
3252 Result ret{}; 3252 Result ret{};
3253 3253
3254 DeviceName device_name{}; 3254 DeviceName device_name{};
3255 Handle das_handle{}; 3255 Handle das_handle{};
3256 3256
3257 device_name = Convert<DeviceName>(GetReg64(system, 0)); 3257 device_name = Convert<DeviceName>(GetArg64(args, 0));
3258 das_handle = Convert<Handle>(GetReg64(system, 1)); 3258 das_handle = Convert<Handle>(GetArg64(args, 1));
3259 3259
3260 ret = AttachDeviceAddressSpace64(system, device_name, das_handle); 3260 ret = AttachDeviceAddressSpace64(system, device_name, das_handle);
3261 3261
3262 SetReg64(system, 0, Convert<uint64_t>(ret)); 3262 SetArg64(args, 0, Convert<uint64_t>(ret));
3263} 3263}
3264 3264
3265static void SvcWrap_DetachDeviceAddressSpace64(Core::System& system) { 3265static void SvcWrap_DetachDeviceAddressSpace64(Core::System& system, std::span<uint64_t, 8> args) {
3266 Result ret{}; 3266 Result ret{};
3267 3267
3268 DeviceName device_name{}; 3268 DeviceName device_name{};
3269 Handle das_handle{}; 3269 Handle das_handle{};
3270 3270
3271 device_name = Convert<DeviceName>(GetReg64(system, 0)); 3271 device_name = Convert<DeviceName>(GetArg64(args, 0));
3272 das_handle = Convert<Handle>(GetReg64(system, 1)); 3272 das_handle = Convert<Handle>(GetArg64(args, 1));
3273 3273
3274 ret = DetachDeviceAddressSpace64(system, device_name, das_handle); 3274 ret = DetachDeviceAddressSpace64(system, device_name, das_handle);
3275 3275
3276 SetReg64(system, 0, Convert<uint64_t>(ret)); 3276 SetArg64(args, 0, Convert<uint64_t>(ret));
3277} 3277}
3278 3278
3279static void SvcWrap_MapDeviceAddressSpaceByForce64(Core::System& system) { 3279static void SvcWrap_MapDeviceAddressSpaceByForce64(Core::System& system, std::span<uint64_t, 8> args) {
3280 Result ret{}; 3280 Result ret{};
3281 3281
3282 Handle das_handle{}; 3282 Handle das_handle{};
@@ -3286,19 +3286,19 @@ static void SvcWrap_MapDeviceAddressSpaceByForce64(Core::System& system) {
3286 uint64_t device_address{}; 3286 uint64_t device_address{};
3287 uint32_t option{}; 3287 uint32_t option{};
3288 3288
3289 das_handle = Convert<Handle>(GetReg64(system, 0)); 3289 das_handle = Convert<Handle>(GetArg64(args, 0));
3290 process_handle = Convert<Handle>(GetReg64(system, 1)); 3290 process_handle = Convert<Handle>(GetArg64(args, 1));
3291 process_address = Convert<uint64_t>(GetReg64(system, 2)); 3291 process_address = Convert<uint64_t>(GetArg64(args, 2));
3292 size = Convert<uint64_t>(GetReg64(system, 3)); 3292 size = Convert<uint64_t>(GetArg64(args, 3));
3293 device_address = Convert<uint64_t>(GetReg64(system, 4)); 3293 device_address = Convert<uint64_t>(GetArg64(args, 4));
3294 option = Convert<uint32_t>(GetReg64(system, 5)); 3294 option = Convert<uint32_t>(GetArg64(args, 5));
3295 3295
3296 ret = MapDeviceAddressSpaceByForce64(system, das_handle, process_handle, process_address, size, device_address, option); 3296 ret = MapDeviceAddressSpaceByForce64(system, das_handle, process_handle, process_address, size, device_address, option);
3297 3297
3298 SetReg64(system, 0, Convert<uint64_t>(ret)); 3298 SetArg64(args, 0, Convert<uint64_t>(ret));
3299} 3299}
3300 3300
3301static void SvcWrap_MapDeviceAddressSpaceAligned64(Core::System& system) { 3301static void SvcWrap_MapDeviceAddressSpaceAligned64(Core::System& system, std::span<uint64_t, 8> args) {
3302 Result ret{}; 3302 Result ret{};
3303 3303
3304 Handle das_handle{}; 3304 Handle das_handle{};
@@ -3308,19 +3308,19 @@ static void SvcWrap_MapDeviceAddressSpaceAligned64(Core::System& system) {
3308 uint64_t device_address{}; 3308 uint64_t device_address{};
3309 uint32_t option{}; 3309 uint32_t option{};
3310 3310
3311 das_handle = Convert<Handle>(GetReg64(system, 0)); 3311 das_handle = Convert<Handle>(GetArg64(args, 0));
3312 process_handle = Convert<Handle>(GetReg64(system, 1)); 3312 process_handle = Convert<Handle>(GetArg64(args, 1));
3313 process_address = Convert<uint64_t>(GetReg64(system, 2)); 3313 process_address = Convert<uint64_t>(GetArg64(args, 2));
3314 size = Convert<uint64_t>(GetReg64(system, 3)); 3314 size = Convert<uint64_t>(GetArg64(args, 3));
3315 device_address = Convert<uint64_t>(GetReg64(system, 4)); 3315 device_address = Convert<uint64_t>(GetArg64(args, 4));
3316 option = Convert<uint32_t>(GetReg64(system, 5)); 3316 option = Convert<uint32_t>(GetArg64(args, 5));
3317 3317
3318 ret = MapDeviceAddressSpaceAligned64(system, das_handle, process_handle, process_address, size, device_address, option); 3318 ret = MapDeviceAddressSpaceAligned64(system, das_handle, process_handle, process_address, size, device_address, option);
3319 3319
3320 SetReg64(system, 0, Convert<uint64_t>(ret)); 3320 SetArg64(args, 0, Convert<uint64_t>(ret));
3321} 3321}
3322 3322
3323static void SvcWrap_UnmapDeviceAddressSpace64(Core::System& system) { 3323static void SvcWrap_UnmapDeviceAddressSpace64(Core::System& system, std::span<uint64_t, 8> args) {
3324 Result ret{}; 3324 Result ret{};
3325 3325
3326 Handle das_handle{}; 3326 Handle das_handle{};
@@ -3329,118 +3329,118 @@ static void SvcWrap_UnmapDeviceAddressSpace64(Core::System& system) {
3329 uint64_t size{}; 3329 uint64_t size{};
3330 uint64_t device_address{}; 3330 uint64_t device_address{};
3331 3331
3332 das_handle = Convert<Handle>(GetReg64(system, 0)); 3332 das_handle = Convert<Handle>(GetArg64(args, 0));
3333 process_handle = Convert<Handle>(GetReg64(system, 1)); 3333 process_handle = Convert<Handle>(GetArg64(args, 1));
3334 process_address = Convert<uint64_t>(GetReg64(system, 2)); 3334 process_address = Convert<uint64_t>(GetArg64(args, 2));
3335 size = Convert<uint64_t>(GetReg64(system, 3)); 3335 size = Convert<uint64_t>(GetArg64(args, 3));
3336 device_address = Convert<uint64_t>(GetReg64(system, 4)); 3336 device_address = Convert<uint64_t>(GetArg64(args, 4));
3337 3337
3338 ret = UnmapDeviceAddressSpace64(system, das_handle, process_handle, process_address, size, device_address); 3338 ret = UnmapDeviceAddressSpace64(system, das_handle, process_handle, process_address, size, device_address);
3339 3339
3340 SetReg64(system, 0, Convert<uint64_t>(ret)); 3340 SetArg64(args, 0, Convert<uint64_t>(ret));
3341} 3341}
3342 3342
3343static void SvcWrap_InvalidateProcessDataCache64(Core::System& system) { 3343static void SvcWrap_InvalidateProcessDataCache64(Core::System& system, std::span<uint64_t, 8> args) {
3344 Result ret{}; 3344 Result ret{};
3345 3345
3346 Handle process_handle{}; 3346 Handle process_handle{};
3347 uint64_t address{}; 3347 uint64_t address{};
3348 uint64_t size{}; 3348 uint64_t size{};
3349 3349
3350 process_handle = Convert<Handle>(GetReg64(system, 0)); 3350 process_handle = Convert<Handle>(GetArg64(args, 0));
3351 address = Convert<uint64_t>(GetReg64(system, 1)); 3351 address = Convert<uint64_t>(GetArg64(args, 1));
3352 size = Convert<uint64_t>(GetReg64(system, 2)); 3352 size = Convert<uint64_t>(GetArg64(args, 2));
3353 3353
3354 ret = InvalidateProcessDataCache64(system, process_handle, address, size); 3354 ret = InvalidateProcessDataCache64(system, process_handle, address, size);
3355 3355
3356 SetReg64(system, 0, Convert<uint64_t>(ret)); 3356 SetArg64(args, 0, Convert<uint64_t>(ret));
3357} 3357}
3358 3358
3359static void SvcWrap_StoreProcessDataCache64(Core::System& system) { 3359static void SvcWrap_StoreProcessDataCache64(Core::System& system, std::span<uint64_t, 8> args) {
3360 Result ret{}; 3360 Result ret{};
3361 3361
3362 Handle process_handle{}; 3362 Handle process_handle{};
3363 uint64_t address{}; 3363 uint64_t address{};
3364 uint64_t size{}; 3364 uint64_t size{};
3365 3365
3366 process_handle = Convert<Handle>(GetReg64(system, 0)); 3366 process_handle = Convert<Handle>(GetArg64(args, 0));
3367 address = Convert<uint64_t>(GetReg64(system, 1)); 3367 address = Convert<uint64_t>(GetArg64(args, 1));
3368 size = Convert<uint64_t>(GetReg64(system, 2)); 3368 size = Convert<uint64_t>(GetArg64(args, 2));
3369 3369
3370 ret = StoreProcessDataCache64(system, process_handle, address, size); 3370 ret = StoreProcessDataCache64(system, process_handle, address, size);
3371 3371
3372 SetReg64(system, 0, Convert<uint64_t>(ret)); 3372 SetArg64(args, 0, Convert<uint64_t>(ret));
3373} 3373}
3374 3374
3375static void SvcWrap_FlushProcessDataCache64(Core::System& system) { 3375static void SvcWrap_FlushProcessDataCache64(Core::System& system, std::span<uint64_t, 8> args) {
3376 Result ret{}; 3376 Result ret{};
3377 3377
3378 Handle process_handle{}; 3378 Handle process_handle{};
3379 uint64_t address{}; 3379 uint64_t address{};
3380 uint64_t size{}; 3380 uint64_t size{};
3381 3381
3382 process_handle = Convert<Handle>(GetReg64(system, 0)); 3382 process_handle = Convert<Handle>(GetArg64(args, 0));
3383 address = Convert<uint64_t>(GetReg64(system, 1)); 3383 address = Convert<uint64_t>(GetArg64(args, 1));
3384 size = Convert<uint64_t>(GetReg64(system, 2)); 3384 size = Convert<uint64_t>(GetArg64(args, 2));
3385 3385
3386 ret = FlushProcessDataCache64(system, process_handle, address, size); 3386 ret = FlushProcessDataCache64(system, process_handle, address, size);
3387 3387
3388 SetReg64(system, 0, Convert<uint64_t>(ret)); 3388 SetArg64(args, 0, Convert<uint64_t>(ret));
3389} 3389}
3390 3390
3391static void SvcWrap_DebugActiveProcess64(Core::System& system) { 3391static void SvcWrap_DebugActiveProcess64(Core::System& system, std::span<uint64_t, 8> args) {
3392 Result ret{}; 3392 Result ret{};
3393 3393
3394 Handle out_handle{}; 3394 Handle out_handle{};
3395 uint64_t process_id{}; 3395 uint64_t process_id{};
3396 3396
3397 process_id = Convert<uint64_t>(GetReg64(system, 1)); 3397 process_id = Convert<uint64_t>(GetArg64(args, 1));
3398 3398
3399 ret = DebugActiveProcess64(system, std::addressof(out_handle), process_id); 3399 ret = DebugActiveProcess64(system, std::addressof(out_handle), process_id);
3400 3400
3401 SetReg64(system, 0, Convert<uint64_t>(ret)); 3401 SetArg64(args, 0, Convert<uint64_t>(ret));
3402 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 3402 SetArg64(args, 1, Convert<uint64_t>(out_handle));
3403} 3403}
3404 3404
3405static void SvcWrap_BreakDebugProcess64(Core::System& system) { 3405static void SvcWrap_BreakDebugProcess64(Core::System& system, std::span<uint64_t, 8> args) {
3406 Result ret{}; 3406 Result ret{};
3407 3407
3408 Handle debug_handle{}; 3408 Handle debug_handle{};
3409 3409
3410 debug_handle = Convert<Handle>(GetReg64(system, 0)); 3410 debug_handle = Convert<Handle>(GetArg64(args, 0));
3411 3411
3412 ret = BreakDebugProcess64(system, debug_handle); 3412 ret = BreakDebugProcess64(system, debug_handle);
3413 3413
3414 SetReg64(system, 0, Convert<uint64_t>(ret)); 3414 SetArg64(args, 0, Convert<uint64_t>(ret));
3415} 3415}
3416 3416
3417static void SvcWrap_TerminateDebugProcess64(Core::System& system) { 3417static void SvcWrap_TerminateDebugProcess64(Core::System& system, std::span<uint64_t, 8> args) {
3418 Result ret{}; 3418 Result ret{};
3419 3419
3420 Handle debug_handle{}; 3420 Handle debug_handle{};
3421 3421
3422 debug_handle = Convert<Handle>(GetReg64(system, 0)); 3422 debug_handle = Convert<Handle>(GetArg64(args, 0));
3423 3423
3424 ret = TerminateDebugProcess64(system, debug_handle); 3424 ret = TerminateDebugProcess64(system, debug_handle);
3425 3425
3426 SetReg64(system, 0, Convert<uint64_t>(ret)); 3426 SetArg64(args, 0, Convert<uint64_t>(ret));
3427} 3427}
3428 3428
3429static void SvcWrap_GetDebugEvent64(Core::System& system) { 3429static void SvcWrap_GetDebugEvent64(Core::System& system, std::span<uint64_t, 8> args) {
3430 Result ret{}; 3430 Result ret{};
3431 3431
3432 uint64_t out_info{}; 3432 uint64_t out_info{};
3433 Handle debug_handle{}; 3433 Handle debug_handle{};
3434 3434
3435 out_info = Convert<uint64_t>(GetReg64(system, 0)); 3435 out_info = Convert<uint64_t>(GetArg64(args, 0));
3436 debug_handle = Convert<Handle>(GetReg64(system, 1)); 3436 debug_handle = Convert<Handle>(GetArg64(args, 1));
3437 3437
3438 ret = GetDebugEvent64(system, out_info, debug_handle); 3438 ret = GetDebugEvent64(system, out_info, debug_handle);
3439 3439
3440 SetReg64(system, 0, Convert<uint64_t>(ret)); 3440 SetArg64(args, 0, Convert<uint64_t>(ret));
3441} 3441}
3442 3442
3443static void SvcWrap_ContinueDebugEvent64(Core::System& system) { 3443static void SvcWrap_ContinueDebugEvent64(Core::System& system, std::span<uint64_t, 8> args) {
3444 Result ret{}; 3444 Result ret{};
3445 3445
3446 Handle debug_handle{}; 3446 Handle debug_handle{};
@@ -3448,33 +3448,33 @@ static void SvcWrap_ContinueDebugEvent64(Core::System& system) {
3448 uint64_t thread_ids{}; 3448 uint64_t thread_ids{};
3449 int32_t num_thread_ids{}; 3449 int32_t num_thread_ids{};
3450 3450
3451 debug_handle = Convert<Handle>(GetReg64(system, 0)); 3451 debug_handle = Convert<Handle>(GetArg64(args, 0));
3452 flags = Convert<uint32_t>(GetReg64(system, 1)); 3452 flags = Convert<uint32_t>(GetArg64(args, 1));
3453 thread_ids = Convert<uint64_t>(GetReg64(system, 2)); 3453 thread_ids = Convert<uint64_t>(GetArg64(args, 2));
3454 num_thread_ids = Convert<int32_t>(GetReg64(system, 3)); 3454 num_thread_ids = Convert<int32_t>(GetArg64(args, 3));
3455 3455
3456 ret = ContinueDebugEvent64(system, debug_handle, flags, thread_ids, num_thread_ids); 3456 ret = ContinueDebugEvent64(system, debug_handle, flags, thread_ids, num_thread_ids);
3457 3457
3458 SetReg64(system, 0, Convert<uint64_t>(ret)); 3458 SetArg64(args, 0, Convert<uint64_t>(ret));
3459} 3459}
3460 3460
3461static void SvcWrap_GetProcessList64(Core::System& system) { 3461static void SvcWrap_GetProcessList64(Core::System& system, std::span<uint64_t, 8> args) {
3462 Result ret{}; 3462 Result ret{};
3463 3463
3464 int32_t out_num_processes{}; 3464 int32_t out_num_processes{};
3465 uint64_t out_process_ids{}; 3465 uint64_t out_process_ids{};
3466 int32_t max_out_count{}; 3466 int32_t max_out_count{};
3467 3467
3468 out_process_ids = Convert<uint64_t>(GetReg64(system, 1)); 3468 out_process_ids = Convert<uint64_t>(GetArg64(args, 1));
3469 max_out_count = Convert<int32_t>(GetReg64(system, 2)); 3469 max_out_count = Convert<int32_t>(GetArg64(args, 2));
3470 3470
3471 ret = GetProcessList64(system, std::addressof(out_num_processes), out_process_ids, max_out_count); 3471 ret = GetProcessList64(system, std::addressof(out_num_processes), out_process_ids, max_out_count);
3472 3472
3473 SetReg64(system, 0, Convert<uint64_t>(ret)); 3473 SetArg64(args, 0, Convert<uint64_t>(ret));
3474 SetReg64(system, 1, Convert<uint64_t>(out_num_processes)); 3474 SetArg64(args, 1, Convert<uint64_t>(out_num_processes));
3475} 3475}
3476 3476
3477static void SvcWrap_GetThreadList64(Core::System& system) { 3477static void SvcWrap_GetThreadList64(Core::System& system, std::span<uint64_t, 8> args) {
3478 Result ret{}; 3478 Result ret{};
3479 3479
3480 int32_t out_num_threads{}; 3480 int32_t out_num_threads{};
@@ -3482,17 +3482,17 @@ static void SvcWrap_GetThreadList64(Core::System& system) {
3482 int32_t max_out_count{}; 3482 int32_t max_out_count{};
3483 Handle debug_handle{}; 3483 Handle debug_handle{};
3484 3484
3485 out_thread_ids = Convert<uint64_t>(GetReg64(system, 1)); 3485 out_thread_ids = Convert<uint64_t>(GetArg64(args, 1));
3486 max_out_count = Convert<int32_t>(GetReg64(system, 2)); 3486 max_out_count = Convert<int32_t>(GetArg64(args, 2));
3487 debug_handle = Convert<Handle>(GetReg64(system, 3)); 3487 debug_handle = Convert<Handle>(GetArg64(args, 3));
3488 3488
3489 ret = GetThreadList64(system, std::addressof(out_num_threads), out_thread_ids, max_out_count, debug_handle); 3489 ret = GetThreadList64(system, std::addressof(out_num_threads), out_thread_ids, max_out_count, debug_handle);
3490 3490
3491 SetReg64(system, 0, Convert<uint64_t>(ret)); 3491 SetArg64(args, 0, Convert<uint64_t>(ret));
3492 SetReg64(system, 1, Convert<uint64_t>(out_num_threads)); 3492 SetArg64(args, 1, Convert<uint64_t>(out_num_threads));
3493} 3493}
3494 3494
3495static void SvcWrap_GetDebugThreadContext64(Core::System& system) { 3495static void SvcWrap_GetDebugThreadContext64(Core::System& system, std::span<uint64_t, 8> args) {
3496 Result ret{}; 3496 Result ret{};
3497 3497
3498 uint64_t out_context{}; 3498 uint64_t out_context{};
@@ -3500,17 +3500,17 @@ static void SvcWrap_GetDebugThreadContext64(Core::System& system) {
3500 uint64_t thread_id{}; 3500 uint64_t thread_id{};
3501 uint32_t context_flags{}; 3501 uint32_t context_flags{};
3502 3502
3503 out_context = Convert<uint64_t>(GetReg64(system, 0)); 3503 out_context = Convert<uint64_t>(GetArg64(args, 0));
3504 debug_handle = Convert<Handle>(GetReg64(system, 1)); 3504 debug_handle = Convert<Handle>(GetArg64(args, 1));
3505 thread_id = Convert<uint64_t>(GetReg64(system, 2)); 3505 thread_id = Convert<uint64_t>(GetArg64(args, 2));
3506 context_flags = Convert<uint32_t>(GetReg64(system, 3)); 3506 context_flags = Convert<uint32_t>(GetArg64(args, 3));
3507 3507
3508 ret = GetDebugThreadContext64(system, out_context, debug_handle, thread_id, context_flags); 3508 ret = GetDebugThreadContext64(system, out_context, debug_handle, thread_id, context_flags);
3509 3509
3510 SetReg64(system, 0, Convert<uint64_t>(ret)); 3510 SetArg64(args, 0, Convert<uint64_t>(ret));
3511} 3511}
3512 3512
3513static void SvcWrap_SetDebugThreadContext64(Core::System& system) { 3513static void SvcWrap_SetDebugThreadContext64(Core::System& system, std::span<uint64_t, 8> args) {
3514 Result ret{}; 3514 Result ret{};
3515 3515
3516 Handle debug_handle{}; 3516 Handle debug_handle{};
@@ -3518,17 +3518,17 @@ static void SvcWrap_SetDebugThreadContext64(Core::System& system) {
3518 uint64_t context{}; 3518 uint64_t context{};
3519 uint32_t context_flags{}; 3519 uint32_t context_flags{};
3520 3520
3521 debug_handle = Convert<Handle>(GetReg64(system, 0)); 3521 debug_handle = Convert<Handle>(GetArg64(args, 0));
3522 thread_id = Convert<uint64_t>(GetReg64(system, 1)); 3522 thread_id = Convert<uint64_t>(GetArg64(args, 1));
3523 context = Convert<uint64_t>(GetReg64(system, 2)); 3523 context = Convert<uint64_t>(GetArg64(args, 2));
3524 context_flags = Convert<uint32_t>(GetReg64(system, 3)); 3524 context_flags = Convert<uint32_t>(GetArg64(args, 3));
3525 3525
3526 ret = SetDebugThreadContext64(system, debug_handle, thread_id, context, context_flags); 3526 ret = SetDebugThreadContext64(system, debug_handle, thread_id, context, context_flags);
3527 3527
3528 SetReg64(system, 0, Convert<uint64_t>(ret)); 3528 SetArg64(args, 0, Convert<uint64_t>(ret));
3529} 3529}
3530 3530
3531static void SvcWrap_QueryDebugProcessMemory64(Core::System& system) { 3531static void SvcWrap_QueryDebugProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3532 Result ret{}; 3532 Result ret{};
3533 3533
3534 PageInfo out_page_info{}; 3534 PageInfo out_page_info{};
@@ -3536,17 +3536,17 @@ static void SvcWrap_QueryDebugProcessMemory64(Core::System& system) {
3536 Handle process_handle{}; 3536 Handle process_handle{};
3537 uint64_t address{}; 3537 uint64_t address{};
3538 3538
3539 out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); 3539 out_memory_info = Convert<uint64_t>(GetArg64(args, 0));
3540 process_handle = Convert<Handle>(GetReg64(system, 2)); 3540 process_handle = Convert<Handle>(GetArg64(args, 2));
3541 address = Convert<uint64_t>(GetReg64(system, 3)); 3541 address = Convert<uint64_t>(GetArg64(args, 3));
3542 3542
3543 ret = QueryDebugProcessMemory64(system, out_memory_info, std::addressof(out_page_info), process_handle, address); 3543 ret = QueryDebugProcessMemory64(system, out_memory_info, std::addressof(out_page_info), process_handle, address);
3544 3544
3545 SetReg64(system, 0, Convert<uint64_t>(ret)); 3545 SetArg64(args, 0, Convert<uint64_t>(ret));
3546 SetReg64(system, 1, Convert<uint64_t>(out_page_info)); 3546 SetArg64(args, 1, Convert<uint64_t>(out_page_info));
3547} 3547}
3548 3548
3549static void SvcWrap_ReadDebugProcessMemory64(Core::System& system) { 3549static void SvcWrap_ReadDebugProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3550 Result ret{}; 3550 Result ret{};
3551 3551
3552 uint64_t buffer{}; 3552 uint64_t buffer{};
@@ -3554,17 +3554,17 @@ static void SvcWrap_ReadDebugProcessMemory64(Core::System& system) {
3554 uint64_t address{}; 3554 uint64_t address{};
3555 uint64_t size{}; 3555 uint64_t size{};
3556 3556
3557 buffer = Convert<uint64_t>(GetReg64(system, 0)); 3557 buffer = Convert<uint64_t>(GetArg64(args, 0));
3558 debug_handle = Convert<Handle>(GetReg64(system, 1)); 3558 debug_handle = Convert<Handle>(GetArg64(args, 1));
3559 address = Convert<uint64_t>(GetReg64(system, 2)); 3559 address = Convert<uint64_t>(GetArg64(args, 2));
3560 size = Convert<uint64_t>(GetReg64(system, 3)); 3560 size = Convert<uint64_t>(GetArg64(args, 3));
3561 3561
3562 ret = ReadDebugProcessMemory64(system, buffer, debug_handle, address, size); 3562 ret = ReadDebugProcessMemory64(system, buffer, debug_handle, address, size);
3563 3563
3564 SetReg64(system, 0, Convert<uint64_t>(ret)); 3564 SetArg64(args, 0, Convert<uint64_t>(ret));
3565} 3565}
3566 3566
3567static void SvcWrap_WriteDebugProcessMemory64(Core::System& system) { 3567static void SvcWrap_WriteDebugProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3568 Result ret{}; 3568 Result ret{};
3569 3569
3570 Handle debug_handle{}; 3570 Handle debug_handle{};
@@ -3572,33 +3572,33 @@ static void SvcWrap_WriteDebugProcessMemory64(Core::System& system) {
3572 uint64_t address{}; 3572 uint64_t address{};
3573 uint64_t size{}; 3573 uint64_t size{};
3574 3574
3575 debug_handle = Convert<Handle>(GetReg64(system, 0)); 3575 debug_handle = Convert<Handle>(GetArg64(args, 0));
3576 buffer = Convert<uint64_t>(GetReg64(system, 1)); 3576 buffer = Convert<uint64_t>(GetArg64(args, 1));
3577 address = Convert<uint64_t>(GetReg64(system, 2)); 3577 address = Convert<uint64_t>(GetArg64(args, 2));
3578 size = Convert<uint64_t>(GetReg64(system, 3)); 3578 size = Convert<uint64_t>(GetArg64(args, 3));
3579 3579
3580 ret = WriteDebugProcessMemory64(system, debug_handle, buffer, address, size); 3580 ret = WriteDebugProcessMemory64(system, debug_handle, buffer, address, size);
3581 3581
3582 SetReg64(system, 0, Convert<uint64_t>(ret)); 3582 SetArg64(args, 0, Convert<uint64_t>(ret));
3583} 3583}
3584 3584
3585static void SvcWrap_SetHardwareBreakPoint64(Core::System& system) { 3585static void SvcWrap_SetHardwareBreakPoint64(Core::System& system, std::span<uint64_t, 8> args) {
3586 Result ret{}; 3586 Result ret{};
3587 3587
3588 HardwareBreakPointRegisterName name{}; 3588 HardwareBreakPointRegisterName name{};
3589 uint64_t flags{}; 3589 uint64_t flags{};
3590 uint64_t value{}; 3590 uint64_t value{};
3591 3591
3592 name = Convert<HardwareBreakPointRegisterName>(GetReg64(system, 0)); 3592 name = Convert<HardwareBreakPointRegisterName>(GetArg64(args, 0));
3593 flags = Convert<uint64_t>(GetReg64(system, 1)); 3593 flags = Convert<uint64_t>(GetArg64(args, 1));
3594 value = Convert<uint64_t>(GetReg64(system, 2)); 3594 value = Convert<uint64_t>(GetArg64(args, 2));
3595 3595
3596 ret = SetHardwareBreakPoint64(system, name, flags, value); 3596 ret = SetHardwareBreakPoint64(system, name, flags, value);
3597 3597
3598 SetReg64(system, 0, Convert<uint64_t>(ret)); 3598 SetArg64(args, 0, Convert<uint64_t>(ret));
3599} 3599}
3600 3600
3601static void SvcWrap_GetDebugThreadParam64(Core::System& system) { 3601static void SvcWrap_GetDebugThreadParam64(Core::System& system, std::span<uint64_t, 8> args) {
3602 Result ret{}; 3602 Result ret{};
3603 3603
3604 uint64_t out_64{}; 3604 uint64_t out_64{};
@@ -3607,18 +3607,18 @@ static void SvcWrap_GetDebugThreadParam64(Core::System& system) {
3607 uint64_t thread_id{}; 3607 uint64_t thread_id{};
3608 DebugThreadParam param{}; 3608 DebugThreadParam param{};
3609 3609
3610 debug_handle = Convert<Handle>(GetReg64(system, 2)); 3610 debug_handle = Convert<Handle>(GetArg64(args, 2));
3611 thread_id = Convert<uint64_t>(GetReg64(system, 3)); 3611 thread_id = Convert<uint64_t>(GetArg64(args, 3));
3612 param = Convert<DebugThreadParam>(GetReg64(system, 4)); 3612 param = Convert<DebugThreadParam>(GetArg64(args, 4));
3613 3613
3614 ret = GetDebugThreadParam64(system, std::addressof(out_64), std::addressof(out_32), debug_handle, thread_id, param); 3614 ret = GetDebugThreadParam64(system, std::addressof(out_64), std::addressof(out_32), debug_handle, thread_id, param);
3615 3615
3616 SetReg64(system, 0, Convert<uint64_t>(ret)); 3616 SetArg64(args, 0, Convert<uint64_t>(ret));
3617 SetReg64(system, 1, Convert<uint64_t>(out_64)); 3617 SetArg64(args, 1, Convert<uint64_t>(out_64));
3618 SetReg64(system, 2, Convert<uint64_t>(out_32)); 3618 SetArg64(args, 2, Convert<uint64_t>(out_32));
3619} 3619}
3620 3620
3621static void SvcWrap_GetSystemInfo64(Core::System& system) { 3621static void SvcWrap_GetSystemInfo64(Core::System& system, std::span<uint64_t, 8> args) {
3622 Result ret{}; 3622 Result ret{};
3623 3623
3624 uint64_t out{}; 3624 uint64_t out{};
@@ -3626,17 +3626,17 @@ static void SvcWrap_GetSystemInfo64(Core::System& system) {
3626 Handle handle{}; 3626 Handle handle{};
3627 uint64_t info_subtype{}; 3627 uint64_t info_subtype{};
3628 3628
3629 info_type = Convert<SystemInfoType>(GetReg64(system, 1)); 3629 info_type = Convert<SystemInfoType>(GetArg64(args, 1));
3630 handle = Convert<Handle>(GetReg64(system, 2)); 3630 handle = Convert<Handle>(GetArg64(args, 2));
3631 info_subtype = Convert<uint64_t>(GetReg64(system, 3)); 3631 info_subtype = Convert<uint64_t>(GetArg64(args, 3));
3632 3632
3633 ret = GetSystemInfo64(system, std::addressof(out), info_type, handle, info_subtype); 3633 ret = GetSystemInfo64(system, std::addressof(out), info_type, handle, info_subtype);
3634 3634
3635 SetReg64(system, 0, Convert<uint64_t>(ret)); 3635 SetArg64(args, 0, Convert<uint64_t>(ret));
3636 SetReg64(system, 1, Convert<uint64_t>(out)); 3636 SetArg64(args, 1, Convert<uint64_t>(out));
3637} 3637}
3638 3638
3639static void SvcWrap_CreatePort64(Core::System& system) { 3639static void SvcWrap_CreatePort64(Core::System& system, std::span<uint64_t, 8> args) {
3640 Result ret{}; 3640 Result ret{};
3641 3641
3642 Handle out_server_handle{}; 3642 Handle out_server_handle{};
@@ -3645,48 +3645,48 @@ static void SvcWrap_CreatePort64(Core::System& system) {
3645 bool is_light{}; 3645 bool is_light{};
3646 uint64_t name{}; 3646 uint64_t name{};
3647 3647
3648 max_sessions = Convert<int32_t>(GetReg64(system, 2)); 3648 max_sessions = Convert<int32_t>(GetArg64(args, 2));
3649 is_light = Convert<bool>(GetReg64(system, 3)); 3649 is_light = Convert<bool>(GetArg64(args, 3));
3650 name = Convert<uint64_t>(GetReg64(system, 4)); 3650 name = Convert<uint64_t>(GetArg64(args, 4));
3651 3651
3652 ret = CreatePort64(system, std::addressof(out_server_handle), std::addressof(out_client_handle), max_sessions, is_light, name); 3652 ret = CreatePort64(system, std::addressof(out_server_handle), std::addressof(out_client_handle), max_sessions, is_light, name);
3653 3653
3654 SetReg64(system, 0, Convert<uint64_t>(ret)); 3654 SetArg64(args, 0, Convert<uint64_t>(ret));
3655 SetReg64(system, 1, Convert<uint64_t>(out_server_handle)); 3655 SetArg64(args, 1, Convert<uint64_t>(out_server_handle));
3656 SetReg64(system, 2, Convert<uint64_t>(out_client_handle)); 3656 SetArg64(args, 2, Convert<uint64_t>(out_client_handle));
3657} 3657}
3658 3658
3659static void SvcWrap_ManageNamedPort64(Core::System& system) { 3659static void SvcWrap_ManageNamedPort64(Core::System& system, std::span<uint64_t, 8> args) {
3660 Result ret{}; 3660 Result ret{};
3661 3661
3662 Handle out_server_handle{}; 3662 Handle out_server_handle{};
3663 uint64_t name{}; 3663 uint64_t name{};
3664 int32_t max_sessions{}; 3664 int32_t max_sessions{};
3665 3665
3666 name = Convert<uint64_t>(GetReg64(system, 1)); 3666 name = Convert<uint64_t>(GetArg64(args, 1));
3667 max_sessions = Convert<int32_t>(GetReg64(system, 2)); 3667 max_sessions = Convert<int32_t>(GetArg64(args, 2));
3668 3668
3669 ret = ManageNamedPort64(system, std::addressof(out_server_handle), name, max_sessions); 3669 ret = ManageNamedPort64(system, std::addressof(out_server_handle), name, max_sessions);
3670 3670
3671 SetReg64(system, 0, Convert<uint64_t>(ret)); 3671 SetArg64(args, 0, Convert<uint64_t>(ret));
3672 SetReg64(system, 1, Convert<uint64_t>(out_server_handle)); 3672 SetArg64(args, 1, Convert<uint64_t>(out_server_handle));
3673} 3673}
3674 3674
3675static void SvcWrap_ConnectToPort64(Core::System& system) { 3675static void SvcWrap_ConnectToPort64(Core::System& system, std::span<uint64_t, 8> args) {
3676 Result ret{}; 3676 Result ret{};
3677 3677
3678 Handle out_handle{}; 3678 Handle out_handle{};
3679 Handle port{}; 3679 Handle port{};
3680 3680
3681 port = Convert<Handle>(GetReg64(system, 1)); 3681 port = Convert<Handle>(GetArg64(args, 1));
3682 3682
3683 ret = ConnectToPort64(system, std::addressof(out_handle), port); 3683 ret = ConnectToPort64(system, std::addressof(out_handle), port);
3684 3684
3685 SetReg64(system, 0, Convert<uint64_t>(ret)); 3685 SetArg64(args, 0, Convert<uint64_t>(ret));
3686 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 3686 SetArg64(args, 1, Convert<uint64_t>(out_handle));
3687} 3687}
3688 3688
3689static void SvcWrap_SetProcessMemoryPermission64(Core::System& system) { 3689static void SvcWrap_SetProcessMemoryPermission64(Core::System& system, std::span<uint64_t, 8> args) {
3690 Result ret{}; 3690 Result ret{};
3691 3691
3692 Handle process_handle{}; 3692 Handle process_handle{};
@@ -3694,17 +3694,17 @@ static void SvcWrap_SetProcessMemoryPermission64(Core::System& system) {
3694 uint64_t size{}; 3694 uint64_t size{};
3695 MemoryPermission perm{}; 3695 MemoryPermission perm{};
3696 3696
3697 process_handle = Convert<Handle>(GetReg64(system, 0)); 3697 process_handle = Convert<Handle>(GetArg64(args, 0));
3698 address = Convert<uint64_t>(GetReg64(system, 1)); 3698 address = Convert<uint64_t>(GetArg64(args, 1));
3699 size = Convert<uint64_t>(GetReg64(system, 2)); 3699 size = Convert<uint64_t>(GetArg64(args, 2));
3700 perm = Convert<MemoryPermission>(GetReg64(system, 3)); 3700 perm = Convert<MemoryPermission>(GetArg64(args, 3));
3701 3701
3702 ret = SetProcessMemoryPermission64(system, process_handle, address, size, perm); 3702 ret = SetProcessMemoryPermission64(system, process_handle, address, size, perm);
3703 3703
3704 SetReg64(system, 0, Convert<uint64_t>(ret)); 3704 SetArg64(args, 0, Convert<uint64_t>(ret));
3705} 3705}
3706 3706
3707static void SvcWrap_MapProcessMemory64(Core::System& system) { 3707static void SvcWrap_MapProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3708 Result ret{}; 3708 Result ret{};
3709 3709
3710 uint64_t dst_address{}; 3710 uint64_t dst_address{};
@@ -3712,17 +3712,17 @@ static void SvcWrap_MapProcessMemory64(Core::System& system) {
3712 uint64_t src_address{}; 3712 uint64_t src_address{};
3713 uint64_t size{}; 3713 uint64_t size{};
3714 3714
3715 dst_address = Convert<uint64_t>(GetReg64(system, 0)); 3715 dst_address = Convert<uint64_t>(GetArg64(args, 0));
3716 process_handle = Convert<Handle>(GetReg64(system, 1)); 3716 process_handle = Convert<Handle>(GetArg64(args, 1));
3717 src_address = Convert<uint64_t>(GetReg64(system, 2)); 3717 src_address = Convert<uint64_t>(GetArg64(args, 2));
3718 size = Convert<uint64_t>(GetReg64(system, 3)); 3718 size = Convert<uint64_t>(GetArg64(args, 3));
3719 3719
3720 ret = MapProcessMemory64(system, dst_address, process_handle, src_address, size); 3720 ret = MapProcessMemory64(system, dst_address, process_handle, src_address, size);
3721 3721
3722 SetReg64(system, 0, Convert<uint64_t>(ret)); 3722 SetArg64(args, 0, Convert<uint64_t>(ret));
3723} 3723}
3724 3724
3725static void SvcWrap_UnmapProcessMemory64(Core::System& system) { 3725static void SvcWrap_UnmapProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3726 Result ret{}; 3726 Result ret{};
3727 3727
3728 uint64_t dst_address{}; 3728 uint64_t dst_address{};
@@ -3730,17 +3730,17 @@ static void SvcWrap_UnmapProcessMemory64(Core::System& system) {
3730 uint64_t src_address{}; 3730 uint64_t src_address{};
3731 uint64_t size{}; 3731 uint64_t size{};
3732 3732
3733 dst_address = Convert<uint64_t>(GetReg64(system, 0)); 3733 dst_address = Convert<uint64_t>(GetArg64(args, 0));
3734 process_handle = Convert<Handle>(GetReg64(system, 1)); 3734 process_handle = Convert<Handle>(GetArg64(args, 1));
3735 src_address = Convert<uint64_t>(GetReg64(system, 2)); 3735 src_address = Convert<uint64_t>(GetArg64(args, 2));
3736 size = Convert<uint64_t>(GetReg64(system, 3)); 3736 size = Convert<uint64_t>(GetArg64(args, 3));
3737 3737
3738 ret = UnmapProcessMemory64(system, dst_address, process_handle, src_address, size); 3738 ret = UnmapProcessMemory64(system, dst_address, process_handle, src_address, size);
3739 3739
3740 SetReg64(system, 0, Convert<uint64_t>(ret)); 3740 SetArg64(args, 0, Convert<uint64_t>(ret));
3741} 3741}
3742 3742
3743static void SvcWrap_QueryProcessMemory64(Core::System& system) { 3743static void SvcWrap_QueryProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3744 Result ret{}; 3744 Result ret{};
3745 3745
3746 PageInfo out_page_info{}; 3746 PageInfo out_page_info{};
@@ -3748,17 +3748,17 @@ static void SvcWrap_QueryProcessMemory64(Core::System& system) {
3748 Handle process_handle{}; 3748 Handle process_handle{};
3749 uint64_t address{}; 3749 uint64_t address{};
3750 3750
3751 out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); 3751 out_memory_info = Convert<uint64_t>(GetArg64(args, 0));
3752 process_handle = Convert<Handle>(GetReg64(system, 2)); 3752 process_handle = Convert<Handle>(GetArg64(args, 2));
3753 address = Convert<uint64_t>(GetReg64(system, 3)); 3753 address = Convert<uint64_t>(GetArg64(args, 3));
3754 3754
3755 ret = QueryProcessMemory64(system, out_memory_info, std::addressof(out_page_info), process_handle, address); 3755 ret = QueryProcessMemory64(system, out_memory_info, std::addressof(out_page_info), process_handle, address);
3756 3756
3757 SetReg64(system, 0, Convert<uint64_t>(ret)); 3757 SetArg64(args, 0, Convert<uint64_t>(ret));
3758 SetReg64(system, 1, Convert<uint64_t>(out_page_info)); 3758 SetArg64(args, 1, Convert<uint64_t>(out_page_info));
3759} 3759}
3760 3760
3761static void SvcWrap_MapProcessCodeMemory64(Core::System& system) { 3761static void SvcWrap_MapProcessCodeMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3762 Result ret{}; 3762 Result ret{};
3763 3763
3764 Handle process_handle{}; 3764 Handle process_handle{};
@@ -3766,17 +3766,17 @@ static void SvcWrap_MapProcessCodeMemory64(Core::System& system) {
3766 uint64_t src_address{}; 3766 uint64_t src_address{};
3767 uint64_t size{}; 3767 uint64_t size{};
3768 3768
3769 process_handle = Convert<Handle>(GetReg64(system, 0)); 3769 process_handle = Convert<Handle>(GetArg64(args, 0));
3770 dst_address = Convert<uint64_t>(GetReg64(system, 1)); 3770 dst_address = Convert<uint64_t>(GetArg64(args, 1));
3771 src_address = Convert<uint64_t>(GetReg64(system, 2)); 3771 src_address = Convert<uint64_t>(GetArg64(args, 2));
3772 size = Convert<uint64_t>(GetReg64(system, 3)); 3772 size = Convert<uint64_t>(GetArg64(args, 3));
3773 3773
3774 ret = MapProcessCodeMemory64(system, process_handle, dst_address, src_address, size); 3774 ret = MapProcessCodeMemory64(system, process_handle, dst_address, src_address, size);
3775 3775
3776 SetReg64(system, 0, Convert<uint64_t>(ret)); 3776 SetArg64(args, 0, Convert<uint64_t>(ret));
3777} 3777}
3778 3778
3779static void SvcWrap_UnmapProcessCodeMemory64(Core::System& system) { 3779static void SvcWrap_UnmapProcessCodeMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3780 Result ret{}; 3780 Result ret{};
3781 3781
3782 Handle process_handle{}; 3782 Handle process_handle{};
@@ -3784,17 +3784,17 @@ static void SvcWrap_UnmapProcessCodeMemory64(Core::System& system) {
3784 uint64_t src_address{}; 3784 uint64_t src_address{};
3785 uint64_t size{}; 3785 uint64_t size{};
3786 3786
3787 process_handle = Convert<Handle>(GetReg64(system, 0)); 3787 process_handle = Convert<Handle>(GetArg64(args, 0));
3788 dst_address = Convert<uint64_t>(GetReg64(system, 1)); 3788 dst_address = Convert<uint64_t>(GetArg64(args, 1));
3789 src_address = Convert<uint64_t>(GetReg64(system, 2)); 3789 src_address = Convert<uint64_t>(GetArg64(args, 2));
3790 size = Convert<uint64_t>(GetReg64(system, 3)); 3790 size = Convert<uint64_t>(GetArg64(args, 3));
3791 3791
3792 ret = UnmapProcessCodeMemory64(system, process_handle, dst_address, src_address, size); 3792 ret = UnmapProcessCodeMemory64(system, process_handle, dst_address, src_address, size);
3793 3793
3794 SetReg64(system, 0, Convert<uint64_t>(ret)); 3794 SetArg64(args, 0, Convert<uint64_t>(ret));
3795} 3795}
3796 3796
3797static void SvcWrap_CreateProcess64(Core::System& system) { 3797static void SvcWrap_CreateProcess64(Core::System& system, std::span<uint64_t, 8> args) {
3798 Result ret{}; 3798 Result ret{};
3799 3799
3800 Handle out_handle{}; 3800 Handle out_handle{};
@@ -3802,17 +3802,17 @@ static void SvcWrap_CreateProcess64(Core::System& system) {
3802 uint64_t caps{}; 3802 uint64_t caps{};
3803 int32_t num_caps{}; 3803 int32_t num_caps{};
3804 3804
3805 parameters = Convert<uint64_t>(GetReg64(system, 1)); 3805 parameters = Convert<uint64_t>(GetArg64(args, 1));
3806 caps = Convert<uint64_t>(GetReg64(system, 2)); 3806 caps = Convert<uint64_t>(GetArg64(args, 2));
3807 num_caps = Convert<int32_t>(GetReg64(system, 3)); 3807 num_caps = Convert<int32_t>(GetArg64(args, 3));
3808 3808
3809 ret = CreateProcess64(system, std::addressof(out_handle), parameters, caps, num_caps); 3809 ret = CreateProcess64(system, std::addressof(out_handle), parameters, caps, num_caps);
3810 3810
3811 SetReg64(system, 0, Convert<uint64_t>(ret)); 3811 SetArg64(args, 0, Convert<uint64_t>(ret));
3812 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 3812 SetArg64(args, 1, Convert<uint64_t>(out_handle));
3813} 3813}
3814 3814
3815static void SvcWrap_StartProcess64(Core::System& system) { 3815static void SvcWrap_StartProcess64(Core::System& system, std::span<uint64_t, 8> args) {
3816 Result ret{}; 3816 Result ret{};
3817 3817
3818 Handle process_handle{}; 3818 Handle process_handle{};
@@ -3820,601 +3820,601 @@ static void SvcWrap_StartProcess64(Core::System& system) {
3820 int32_t core_id{}; 3820 int32_t core_id{};
3821 uint64_t main_thread_stack_size{}; 3821 uint64_t main_thread_stack_size{};
3822 3822
3823 process_handle = Convert<Handle>(GetReg64(system, 0)); 3823 process_handle = Convert<Handle>(GetArg64(args, 0));
3824 priority = Convert<int32_t>(GetReg64(system, 1)); 3824 priority = Convert<int32_t>(GetArg64(args, 1));
3825 core_id = Convert<int32_t>(GetReg64(system, 2)); 3825 core_id = Convert<int32_t>(GetArg64(args, 2));
3826 main_thread_stack_size = Convert<uint64_t>(GetReg64(system, 3)); 3826 main_thread_stack_size = Convert<uint64_t>(GetArg64(args, 3));
3827 3827
3828 ret = StartProcess64(system, process_handle, priority, core_id, main_thread_stack_size); 3828 ret = StartProcess64(system, process_handle, priority, core_id, main_thread_stack_size);
3829 3829
3830 SetReg64(system, 0, Convert<uint64_t>(ret)); 3830 SetArg64(args, 0, Convert<uint64_t>(ret));
3831} 3831}
3832 3832
3833static void SvcWrap_TerminateProcess64(Core::System& system) { 3833static void SvcWrap_TerminateProcess64(Core::System& system, std::span<uint64_t, 8> args) {
3834 Result ret{}; 3834 Result ret{};
3835 3835
3836 Handle process_handle{}; 3836 Handle process_handle{};
3837 3837
3838 process_handle = Convert<Handle>(GetReg64(system, 0)); 3838 process_handle = Convert<Handle>(GetArg64(args, 0));
3839 3839
3840 ret = TerminateProcess64(system, process_handle); 3840 ret = TerminateProcess64(system, process_handle);
3841 3841
3842 SetReg64(system, 0, Convert<uint64_t>(ret)); 3842 SetArg64(args, 0, Convert<uint64_t>(ret));
3843} 3843}
3844 3844
3845static void SvcWrap_GetProcessInfo64(Core::System& system) { 3845static void SvcWrap_GetProcessInfo64(Core::System& system, std::span<uint64_t, 8> args) {
3846 Result ret{}; 3846 Result ret{};
3847 3847
3848 int64_t out_info{}; 3848 int64_t out_info{};
3849 Handle process_handle{}; 3849 Handle process_handle{};
3850 ProcessInfoType info_type{}; 3850 ProcessInfoType info_type{};
3851 3851
3852 process_handle = Convert<Handle>(GetReg64(system, 1)); 3852 process_handle = Convert<Handle>(GetArg64(args, 1));
3853 info_type = Convert<ProcessInfoType>(GetReg64(system, 2)); 3853 info_type = Convert<ProcessInfoType>(GetArg64(args, 2));
3854 3854
3855 ret = GetProcessInfo64(system, std::addressof(out_info), process_handle, info_type); 3855 ret = GetProcessInfo64(system, std::addressof(out_info), process_handle, info_type);
3856 3856
3857 SetReg64(system, 0, Convert<uint64_t>(ret)); 3857 SetArg64(args, 0, Convert<uint64_t>(ret));
3858 SetReg64(system, 1, Convert<uint64_t>(out_info)); 3858 SetArg64(args, 1, Convert<uint64_t>(out_info));
3859} 3859}
3860 3860
3861static void SvcWrap_CreateResourceLimit64(Core::System& system) { 3861static void SvcWrap_CreateResourceLimit64(Core::System& system, std::span<uint64_t, 8> args) {
3862 Result ret{}; 3862 Result ret{};
3863 3863
3864 Handle out_handle{}; 3864 Handle out_handle{};
3865 3865
3866 ret = CreateResourceLimit64(system, std::addressof(out_handle)); 3866 ret = CreateResourceLimit64(system, std::addressof(out_handle));
3867 3867
3868 SetReg64(system, 0, Convert<uint64_t>(ret)); 3868 SetArg64(args, 0, Convert<uint64_t>(ret));
3869 SetReg64(system, 1, Convert<uint64_t>(out_handle)); 3869 SetArg64(args, 1, Convert<uint64_t>(out_handle));
3870} 3870}
3871 3871
3872static void SvcWrap_SetResourceLimitLimitValue64(Core::System& system) { 3872static void SvcWrap_SetResourceLimitLimitValue64(Core::System& system, std::span<uint64_t, 8> args) {
3873 Result ret{}; 3873 Result ret{};
3874 3874
3875 Handle resource_limit_handle{}; 3875 Handle resource_limit_handle{};
3876 LimitableResource which{}; 3876 LimitableResource which{};
3877 int64_t limit_value{}; 3877 int64_t limit_value{};
3878 3878
3879 resource_limit_handle = Convert<Handle>(GetReg64(system, 0)); 3879 resource_limit_handle = Convert<Handle>(GetArg64(args, 0));
3880 which = Convert<LimitableResource>(GetReg64(system, 1)); 3880 which = Convert<LimitableResource>(GetArg64(args, 1));
3881 limit_value = Convert<int64_t>(GetReg64(system, 2)); 3881 limit_value = Convert<int64_t>(GetArg64(args, 2));
3882 3882
3883 ret = SetResourceLimitLimitValue64(system, resource_limit_handle, which, limit_value); 3883 ret = SetResourceLimitLimitValue64(system, resource_limit_handle, which, limit_value);
3884 3884
3885 SetReg64(system, 0, Convert<uint64_t>(ret)); 3885 SetArg64(args, 0, Convert<uint64_t>(ret));
3886} 3886}
3887 3887
3888static void SvcWrap_MapInsecureMemory64(Core::System& system) { 3888static void SvcWrap_MapInsecureMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3889 Result ret{}; 3889 Result ret{};
3890 3890
3891 uint64_t address{}; 3891 uint64_t address{};
3892 uint64_t size{}; 3892 uint64_t size{};
3893 3893
3894 address = Convert<uint64_t>(GetReg64(system, 0)); 3894 address = Convert<uint64_t>(GetArg64(args, 0));
3895 size = Convert<uint64_t>(GetReg64(system, 1)); 3895 size = Convert<uint64_t>(GetArg64(args, 1));
3896 3896
3897 ret = MapInsecureMemory64(system, address, size); 3897 ret = MapInsecureMemory64(system, address, size);
3898 3898
3899 SetReg64(system, 0, Convert<uint64_t>(ret)); 3899 SetArg64(args, 0, Convert<uint64_t>(ret));
3900} 3900}
3901 3901
3902static void SvcWrap_UnmapInsecureMemory64(Core::System& system) { 3902static void SvcWrap_UnmapInsecureMemory64(Core::System& system, std::span<uint64_t, 8> args) {
3903 Result ret{}; 3903 Result ret{};
3904 3904
3905 uint64_t address{}; 3905 uint64_t address{};
3906 uint64_t size{}; 3906 uint64_t size{};
3907 3907
3908 address = Convert<uint64_t>(GetReg64(system, 0)); 3908 address = Convert<uint64_t>(GetArg64(args, 0));
3909 size = Convert<uint64_t>(GetReg64(system, 1)); 3909 size = Convert<uint64_t>(GetArg64(args, 1));
3910 3910
3911 ret = UnmapInsecureMemory64(system, address, size); 3911 ret = UnmapInsecureMemory64(system, address, size);
3912 3912
3913 SetReg64(system, 0, Convert<uint64_t>(ret)); 3913 SetArg64(args, 0, Convert<uint64_t>(ret));
3914} 3914}
3915 3915
3916static void Call32(Core::System& system, u32 imm) { 3916static void Call32(Core::System& system, u32 imm, std::span<uint64_t, 8> args) {
3917 switch (static_cast<SvcId>(imm)) { 3917 switch (static_cast<SvcId>(imm)) {
3918 case SvcId::SetHeapSize: 3918 case SvcId::SetHeapSize:
3919 return SvcWrap_SetHeapSize64From32(system); 3919 return SvcWrap_SetHeapSize64From32(system, args);
3920 case SvcId::SetMemoryPermission: 3920 case SvcId::SetMemoryPermission:
3921 return SvcWrap_SetMemoryPermission64From32(system); 3921 return SvcWrap_SetMemoryPermission64From32(system, args);
3922 case SvcId::SetMemoryAttribute: 3922 case SvcId::SetMemoryAttribute:
3923 return SvcWrap_SetMemoryAttribute64From32(system); 3923 return SvcWrap_SetMemoryAttribute64From32(system, args);
3924 case SvcId::MapMemory: 3924 case SvcId::MapMemory:
3925 return SvcWrap_MapMemory64From32(system); 3925 return SvcWrap_MapMemory64From32(system, args);
3926 case SvcId::UnmapMemory: 3926 case SvcId::UnmapMemory:
3927 return SvcWrap_UnmapMemory64From32(system); 3927 return SvcWrap_UnmapMemory64From32(system, args);
3928 case SvcId::QueryMemory: 3928 case SvcId::QueryMemory:
3929 return SvcWrap_QueryMemory64From32(system); 3929 return SvcWrap_QueryMemory64From32(system, args);
3930 case SvcId::ExitProcess: 3930 case SvcId::ExitProcess:
3931 return SvcWrap_ExitProcess64From32(system); 3931 return SvcWrap_ExitProcess64From32(system, args);
3932 case SvcId::CreateThread: 3932 case SvcId::CreateThread:
3933 return SvcWrap_CreateThread64From32(system); 3933 return SvcWrap_CreateThread64From32(system, args);
3934 case SvcId::StartThread: 3934 case SvcId::StartThread:
3935 return SvcWrap_StartThread64From32(system); 3935 return SvcWrap_StartThread64From32(system, args);
3936 case SvcId::ExitThread: 3936 case SvcId::ExitThread:
3937 return SvcWrap_ExitThread64From32(system); 3937 return SvcWrap_ExitThread64From32(system, args);
3938 case SvcId::SleepThread: 3938 case SvcId::SleepThread:
3939 return SvcWrap_SleepThread64From32(system); 3939 return SvcWrap_SleepThread64From32(system, args);
3940 case SvcId::GetThreadPriority: 3940 case SvcId::GetThreadPriority:
3941 return SvcWrap_GetThreadPriority64From32(system); 3941 return SvcWrap_GetThreadPriority64From32(system, args);
3942 case SvcId::SetThreadPriority: 3942 case SvcId::SetThreadPriority:
3943 return SvcWrap_SetThreadPriority64From32(system); 3943 return SvcWrap_SetThreadPriority64From32(system, args);
3944 case SvcId::GetThreadCoreMask: 3944 case SvcId::GetThreadCoreMask:
3945 return SvcWrap_GetThreadCoreMask64From32(system); 3945 return SvcWrap_GetThreadCoreMask64From32(system, args);
3946 case SvcId::SetThreadCoreMask: 3946 case SvcId::SetThreadCoreMask:
3947 return SvcWrap_SetThreadCoreMask64From32(system); 3947 return SvcWrap_SetThreadCoreMask64From32(system, args);
3948 case SvcId::GetCurrentProcessorNumber: 3948 case SvcId::GetCurrentProcessorNumber:
3949 return SvcWrap_GetCurrentProcessorNumber64From32(system); 3949 return SvcWrap_GetCurrentProcessorNumber64From32(system, args);
3950 case SvcId::SignalEvent: 3950 case SvcId::SignalEvent:
3951 return SvcWrap_SignalEvent64From32(system); 3951 return SvcWrap_SignalEvent64From32(system, args);
3952 case SvcId::ClearEvent: 3952 case SvcId::ClearEvent:
3953 return SvcWrap_ClearEvent64From32(system); 3953 return SvcWrap_ClearEvent64From32(system, args);
3954 case SvcId::MapSharedMemory: 3954 case SvcId::MapSharedMemory:
3955 return SvcWrap_MapSharedMemory64From32(system); 3955 return SvcWrap_MapSharedMemory64From32(system, args);
3956 case SvcId::UnmapSharedMemory: 3956 case SvcId::UnmapSharedMemory:
3957 return SvcWrap_UnmapSharedMemory64From32(system); 3957 return SvcWrap_UnmapSharedMemory64From32(system, args);
3958 case SvcId::CreateTransferMemory: 3958 case SvcId::CreateTransferMemory:
3959 return SvcWrap_CreateTransferMemory64From32(system); 3959 return SvcWrap_CreateTransferMemory64From32(system, args);
3960 case SvcId::CloseHandle: 3960 case SvcId::CloseHandle:
3961 return SvcWrap_CloseHandle64From32(system); 3961 return SvcWrap_CloseHandle64From32(system, args);
3962 case SvcId::ResetSignal: 3962 case SvcId::ResetSignal:
3963 return SvcWrap_ResetSignal64From32(system); 3963 return SvcWrap_ResetSignal64From32(system, args);
3964 case SvcId::WaitSynchronization: 3964 case SvcId::WaitSynchronization:
3965 return SvcWrap_WaitSynchronization64From32(system); 3965 return SvcWrap_WaitSynchronization64From32(system, args);
3966 case SvcId::CancelSynchronization: 3966 case SvcId::CancelSynchronization:
3967 return SvcWrap_CancelSynchronization64From32(system); 3967 return SvcWrap_CancelSynchronization64From32(system, args);
3968 case SvcId::ArbitrateLock: 3968 case SvcId::ArbitrateLock:
3969 return SvcWrap_ArbitrateLock64From32(system); 3969 return SvcWrap_ArbitrateLock64From32(system, args);
3970 case SvcId::ArbitrateUnlock: 3970 case SvcId::ArbitrateUnlock:
3971 return SvcWrap_ArbitrateUnlock64From32(system); 3971 return SvcWrap_ArbitrateUnlock64From32(system, args);
3972 case SvcId::WaitProcessWideKeyAtomic: 3972 case SvcId::WaitProcessWideKeyAtomic:
3973 return SvcWrap_WaitProcessWideKeyAtomic64From32(system); 3973 return SvcWrap_WaitProcessWideKeyAtomic64From32(system, args);
3974 case SvcId::SignalProcessWideKey: 3974 case SvcId::SignalProcessWideKey:
3975 return SvcWrap_SignalProcessWideKey64From32(system); 3975 return SvcWrap_SignalProcessWideKey64From32(system, args);
3976 case SvcId::GetSystemTick: 3976 case SvcId::GetSystemTick:
3977 return SvcWrap_GetSystemTick64From32(system); 3977 return SvcWrap_GetSystemTick64From32(system, args);
3978 case SvcId::ConnectToNamedPort: 3978 case SvcId::ConnectToNamedPort:
3979 return SvcWrap_ConnectToNamedPort64From32(system); 3979 return SvcWrap_ConnectToNamedPort64From32(system, args);
3980 case SvcId::SendSyncRequestLight: 3980 case SvcId::SendSyncRequestLight:
3981 return SvcWrap_SendSyncRequestLight64From32(system); 3981 return SvcWrap_SendSyncRequestLight64From32(system, args);
3982 case SvcId::SendSyncRequest: 3982 case SvcId::SendSyncRequest:
3983 return SvcWrap_SendSyncRequest64From32(system); 3983 return SvcWrap_SendSyncRequest64From32(system, args);
3984 case SvcId::SendSyncRequestWithUserBuffer: 3984 case SvcId::SendSyncRequestWithUserBuffer:
3985 return SvcWrap_SendSyncRequestWithUserBuffer64From32(system); 3985 return SvcWrap_SendSyncRequestWithUserBuffer64From32(system, args);
3986 case SvcId::SendAsyncRequestWithUserBuffer: 3986 case SvcId::SendAsyncRequestWithUserBuffer:
3987 return SvcWrap_SendAsyncRequestWithUserBuffer64From32(system); 3987 return SvcWrap_SendAsyncRequestWithUserBuffer64From32(system, args);
3988 case SvcId::GetProcessId: 3988 case SvcId::GetProcessId:
3989 return SvcWrap_GetProcessId64From32(system); 3989 return SvcWrap_GetProcessId64From32(system, args);
3990 case SvcId::GetThreadId: 3990 case SvcId::GetThreadId:
3991 return SvcWrap_GetThreadId64From32(system); 3991 return SvcWrap_GetThreadId64From32(system, args);
3992 case SvcId::Break: 3992 case SvcId::Break:
3993 return SvcWrap_Break64From32(system); 3993 return SvcWrap_Break64From32(system, args);
3994 case SvcId::OutputDebugString: 3994 case SvcId::OutputDebugString:
3995 return SvcWrap_OutputDebugString64From32(system); 3995 return SvcWrap_OutputDebugString64From32(system, args);
3996 case SvcId::ReturnFromException: 3996 case SvcId::ReturnFromException:
3997 return SvcWrap_ReturnFromException64From32(system); 3997 return SvcWrap_ReturnFromException64From32(system, args);
3998 case SvcId::GetInfo: 3998 case SvcId::GetInfo:
3999 return SvcWrap_GetInfo64From32(system); 3999 return SvcWrap_GetInfo64From32(system, args);
4000 case SvcId::FlushEntireDataCache: 4000 case SvcId::FlushEntireDataCache:
4001 return SvcWrap_FlushEntireDataCache64From32(system); 4001 return SvcWrap_FlushEntireDataCache64From32(system, args);
4002 case SvcId::FlushDataCache: 4002 case SvcId::FlushDataCache:
4003 return SvcWrap_FlushDataCache64From32(system); 4003 return SvcWrap_FlushDataCache64From32(system, args);
4004 case SvcId::MapPhysicalMemory: 4004 case SvcId::MapPhysicalMemory:
4005 return SvcWrap_MapPhysicalMemory64From32(system); 4005 return SvcWrap_MapPhysicalMemory64From32(system, args);
4006 case SvcId::UnmapPhysicalMemory: 4006 case SvcId::UnmapPhysicalMemory:
4007 return SvcWrap_UnmapPhysicalMemory64From32(system); 4007 return SvcWrap_UnmapPhysicalMemory64From32(system, args);
4008 case SvcId::GetDebugFutureThreadInfo: 4008 case SvcId::GetDebugFutureThreadInfo:
4009 return SvcWrap_GetDebugFutureThreadInfo64From32(system); 4009 return SvcWrap_GetDebugFutureThreadInfo64From32(system, args);
4010 case SvcId::GetLastThreadInfo: 4010 case SvcId::GetLastThreadInfo:
4011 return SvcWrap_GetLastThreadInfo64From32(system); 4011 return SvcWrap_GetLastThreadInfo64From32(system, args);
4012 case SvcId::GetResourceLimitLimitValue: 4012 case SvcId::GetResourceLimitLimitValue:
4013 return SvcWrap_GetResourceLimitLimitValue64From32(system); 4013 return SvcWrap_GetResourceLimitLimitValue64From32(system, args);
4014 case SvcId::GetResourceLimitCurrentValue: 4014 case SvcId::GetResourceLimitCurrentValue:
4015 return SvcWrap_GetResourceLimitCurrentValue64From32(system); 4015 return SvcWrap_GetResourceLimitCurrentValue64From32(system, args);
4016 case SvcId::SetThreadActivity: 4016 case SvcId::SetThreadActivity:
4017 return SvcWrap_SetThreadActivity64From32(system); 4017 return SvcWrap_SetThreadActivity64From32(system, args);
4018 case SvcId::GetThreadContext3: 4018 case SvcId::GetThreadContext3:
4019 return SvcWrap_GetThreadContext364From32(system); 4019 return SvcWrap_GetThreadContext364From32(system, args);
4020 case SvcId::WaitForAddress: 4020 case SvcId::WaitForAddress:
4021 return SvcWrap_WaitForAddress64From32(system); 4021 return SvcWrap_WaitForAddress64From32(system, args);
4022 case SvcId::SignalToAddress: 4022 case SvcId::SignalToAddress:
4023 return SvcWrap_SignalToAddress64From32(system); 4023 return SvcWrap_SignalToAddress64From32(system, args);
4024 case SvcId::SynchronizePreemptionState: 4024 case SvcId::SynchronizePreemptionState:
4025 return SvcWrap_SynchronizePreemptionState64From32(system); 4025 return SvcWrap_SynchronizePreemptionState64From32(system, args);
4026 case SvcId::GetResourceLimitPeakValue: 4026 case SvcId::GetResourceLimitPeakValue:
4027 return SvcWrap_GetResourceLimitPeakValue64From32(system); 4027 return SvcWrap_GetResourceLimitPeakValue64From32(system, args);
4028 case SvcId::CreateIoPool: 4028 case SvcId::CreateIoPool:
4029 return SvcWrap_CreateIoPool64From32(system); 4029 return SvcWrap_CreateIoPool64From32(system, args);
4030 case SvcId::CreateIoRegion: 4030 case SvcId::CreateIoRegion:
4031 return SvcWrap_CreateIoRegion64From32(system); 4031 return SvcWrap_CreateIoRegion64From32(system, args);
4032 case SvcId::KernelDebug: 4032 case SvcId::KernelDebug:
4033 return SvcWrap_KernelDebug64From32(system); 4033 return SvcWrap_KernelDebug64From32(system, args);
4034 case SvcId::ChangeKernelTraceState: 4034 case SvcId::ChangeKernelTraceState:
4035 return SvcWrap_ChangeKernelTraceState64From32(system); 4035 return SvcWrap_ChangeKernelTraceState64From32(system, args);
4036 case SvcId::CreateSession: 4036 case SvcId::CreateSession:
4037 return SvcWrap_CreateSession64From32(system); 4037 return SvcWrap_CreateSession64From32(system, args);
4038 case SvcId::AcceptSession: 4038 case SvcId::AcceptSession:
4039 return SvcWrap_AcceptSession64From32(system); 4039 return SvcWrap_AcceptSession64From32(system, args);
4040 case SvcId::ReplyAndReceiveLight: 4040 case SvcId::ReplyAndReceiveLight:
4041 return SvcWrap_ReplyAndReceiveLight64From32(system); 4041 return SvcWrap_ReplyAndReceiveLight64From32(system, args);
4042 case SvcId::ReplyAndReceive: 4042 case SvcId::ReplyAndReceive:
4043 return SvcWrap_ReplyAndReceive64From32(system); 4043 return SvcWrap_ReplyAndReceive64From32(system, args);
4044 case SvcId::ReplyAndReceiveWithUserBuffer: 4044 case SvcId::ReplyAndReceiveWithUserBuffer:
4045 return SvcWrap_ReplyAndReceiveWithUserBuffer64From32(system); 4045 return SvcWrap_ReplyAndReceiveWithUserBuffer64From32(system, args);
4046 case SvcId::CreateEvent: 4046 case SvcId::CreateEvent:
4047 return SvcWrap_CreateEvent64From32(system); 4047 return SvcWrap_CreateEvent64From32(system, args);
4048 case SvcId::MapIoRegion: 4048 case SvcId::MapIoRegion:
4049 return SvcWrap_MapIoRegion64From32(system); 4049 return SvcWrap_MapIoRegion64From32(system, args);
4050 case SvcId::UnmapIoRegion: 4050 case SvcId::UnmapIoRegion:
4051 return SvcWrap_UnmapIoRegion64From32(system); 4051 return SvcWrap_UnmapIoRegion64From32(system, args);
4052 case SvcId::MapPhysicalMemoryUnsafe: 4052 case SvcId::MapPhysicalMemoryUnsafe:
4053 return SvcWrap_MapPhysicalMemoryUnsafe64From32(system); 4053 return SvcWrap_MapPhysicalMemoryUnsafe64From32(system, args);
4054 case SvcId::UnmapPhysicalMemoryUnsafe: 4054 case SvcId::UnmapPhysicalMemoryUnsafe:
4055 return SvcWrap_UnmapPhysicalMemoryUnsafe64From32(system); 4055 return SvcWrap_UnmapPhysicalMemoryUnsafe64From32(system, args);
4056 case SvcId::SetUnsafeLimit: 4056 case SvcId::SetUnsafeLimit:
4057 return SvcWrap_SetUnsafeLimit64From32(system); 4057 return SvcWrap_SetUnsafeLimit64From32(system, args);
4058 case SvcId::CreateCodeMemory: 4058 case SvcId::CreateCodeMemory:
4059 return SvcWrap_CreateCodeMemory64From32(system); 4059 return SvcWrap_CreateCodeMemory64From32(system, args);
4060 case SvcId::ControlCodeMemory: 4060 case SvcId::ControlCodeMemory:
4061 return SvcWrap_ControlCodeMemory64From32(system); 4061 return SvcWrap_ControlCodeMemory64From32(system, args);
4062 case SvcId::SleepSystem: 4062 case SvcId::SleepSystem:
4063 return SvcWrap_SleepSystem64From32(system); 4063 return SvcWrap_SleepSystem64From32(system, args);
4064 case SvcId::ReadWriteRegister: 4064 case SvcId::ReadWriteRegister:
4065 return SvcWrap_ReadWriteRegister64From32(system); 4065 return SvcWrap_ReadWriteRegister64From32(system, args);
4066 case SvcId::SetProcessActivity: 4066 case SvcId::SetProcessActivity:
4067 return SvcWrap_SetProcessActivity64From32(system); 4067 return SvcWrap_SetProcessActivity64From32(system, args);
4068 case SvcId::CreateSharedMemory: 4068 case SvcId::CreateSharedMemory:
4069 return SvcWrap_CreateSharedMemory64From32(system); 4069 return SvcWrap_CreateSharedMemory64From32(system, args);
4070 case SvcId::MapTransferMemory: 4070 case SvcId::MapTransferMemory:
4071 return SvcWrap_MapTransferMemory64From32(system); 4071 return SvcWrap_MapTransferMemory64From32(system, args);
4072 case SvcId::UnmapTransferMemory: 4072 case SvcId::UnmapTransferMemory:
4073 return SvcWrap_UnmapTransferMemory64From32(system); 4073 return SvcWrap_UnmapTransferMemory64From32(system, args);
4074 case SvcId::CreateInterruptEvent: 4074 case SvcId::CreateInterruptEvent:
4075 return SvcWrap_CreateInterruptEvent64From32(system); 4075 return SvcWrap_CreateInterruptEvent64From32(system, args);
4076 case SvcId::QueryPhysicalAddress: 4076 case SvcId::QueryPhysicalAddress:
4077 return SvcWrap_QueryPhysicalAddress64From32(system); 4077 return SvcWrap_QueryPhysicalAddress64From32(system, args);
4078 case SvcId::QueryIoMapping: 4078 case SvcId::QueryIoMapping:
4079 return SvcWrap_QueryIoMapping64From32(system); 4079 return SvcWrap_QueryIoMapping64From32(system, args);
4080 case SvcId::CreateDeviceAddressSpace: 4080 case SvcId::CreateDeviceAddressSpace:
4081 return SvcWrap_CreateDeviceAddressSpace64From32(system); 4081 return SvcWrap_CreateDeviceAddressSpace64From32(system, args);
4082 case SvcId::AttachDeviceAddressSpace: 4082 case SvcId::AttachDeviceAddressSpace:
4083 return SvcWrap_AttachDeviceAddressSpace64From32(system); 4083 return SvcWrap_AttachDeviceAddressSpace64From32(system, args);
4084 case SvcId::DetachDeviceAddressSpace: 4084 case SvcId::DetachDeviceAddressSpace:
4085 return SvcWrap_DetachDeviceAddressSpace64From32(system); 4085 return SvcWrap_DetachDeviceAddressSpace64From32(system, args);
4086 case SvcId::MapDeviceAddressSpaceByForce: 4086 case SvcId::MapDeviceAddressSpaceByForce:
4087 return SvcWrap_MapDeviceAddressSpaceByForce64From32(system); 4087 return SvcWrap_MapDeviceAddressSpaceByForce64From32(system, args);
4088 case SvcId::MapDeviceAddressSpaceAligned: 4088 case SvcId::MapDeviceAddressSpaceAligned:
4089 return SvcWrap_MapDeviceAddressSpaceAligned64From32(system); 4089 return SvcWrap_MapDeviceAddressSpaceAligned64From32(system, args);
4090 case SvcId::UnmapDeviceAddressSpace: 4090 case SvcId::UnmapDeviceAddressSpace:
4091 return SvcWrap_UnmapDeviceAddressSpace64From32(system); 4091 return SvcWrap_UnmapDeviceAddressSpace64From32(system, args);
4092 case SvcId::InvalidateProcessDataCache: 4092 case SvcId::InvalidateProcessDataCache:
4093 return SvcWrap_InvalidateProcessDataCache64From32(system); 4093 return SvcWrap_InvalidateProcessDataCache64From32(system, args);
4094 case SvcId::StoreProcessDataCache: 4094 case SvcId::StoreProcessDataCache:
4095 return SvcWrap_StoreProcessDataCache64From32(system); 4095 return SvcWrap_StoreProcessDataCache64From32(system, args);
4096 case SvcId::FlushProcessDataCache: 4096 case SvcId::FlushProcessDataCache:
4097 return SvcWrap_FlushProcessDataCache64From32(system); 4097 return SvcWrap_FlushProcessDataCache64From32(system, args);
4098 case SvcId::DebugActiveProcess: 4098 case SvcId::DebugActiveProcess:
4099 return SvcWrap_DebugActiveProcess64From32(system); 4099 return SvcWrap_DebugActiveProcess64From32(system, args);
4100 case SvcId::BreakDebugProcess: 4100 case SvcId::BreakDebugProcess:
4101 return SvcWrap_BreakDebugProcess64From32(system); 4101 return SvcWrap_BreakDebugProcess64From32(system, args);
4102 case SvcId::TerminateDebugProcess: 4102 case SvcId::TerminateDebugProcess:
4103 return SvcWrap_TerminateDebugProcess64From32(system); 4103 return SvcWrap_TerminateDebugProcess64From32(system, args);
4104 case SvcId::GetDebugEvent: 4104 case SvcId::GetDebugEvent:
4105 return SvcWrap_GetDebugEvent64From32(system); 4105 return SvcWrap_GetDebugEvent64From32(system, args);
4106 case SvcId::ContinueDebugEvent: 4106 case SvcId::ContinueDebugEvent:
4107 return SvcWrap_ContinueDebugEvent64From32(system); 4107 return SvcWrap_ContinueDebugEvent64From32(system, args);
4108 case SvcId::GetProcessList: 4108 case SvcId::GetProcessList:
4109 return SvcWrap_GetProcessList64From32(system); 4109 return SvcWrap_GetProcessList64From32(system, args);
4110 case SvcId::GetThreadList: 4110 case SvcId::GetThreadList:
4111 return SvcWrap_GetThreadList64From32(system); 4111 return SvcWrap_GetThreadList64From32(system, args);
4112 case SvcId::GetDebugThreadContext: 4112 case SvcId::GetDebugThreadContext:
4113 return SvcWrap_GetDebugThreadContext64From32(system); 4113 return SvcWrap_GetDebugThreadContext64From32(system, args);
4114 case SvcId::SetDebugThreadContext: 4114 case SvcId::SetDebugThreadContext:
4115 return SvcWrap_SetDebugThreadContext64From32(system); 4115 return SvcWrap_SetDebugThreadContext64From32(system, args);
4116 case SvcId::QueryDebugProcessMemory: 4116 case SvcId::QueryDebugProcessMemory:
4117 return SvcWrap_QueryDebugProcessMemory64From32(system); 4117 return SvcWrap_QueryDebugProcessMemory64From32(system, args);
4118 case SvcId::ReadDebugProcessMemory: 4118 case SvcId::ReadDebugProcessMemory:
4119 return SvcWrap_ReadDebugProcessMemory64From32(system); 4119 return SvcWrap_ReadDebugProcessMemory64From32(system, args);
4120 case SvcId::WriteDebugProcessMemory: 4120 case SvcId::WriteDebugProcessMemory:
4121 return SvcWrap_WriteDebugProcessMemory64From32(system); 4121 return SvcWrap_WriteDebugProcessMemory64From32(system, args);
4122 case SvcId::SetHardwareBreakPoint: 4122 case SvcId::SetHardwareBreakPoint:
4123 return SvcWrap_SetHardwareBreakPoint64From32(system); 4123 return SvcWrap_SetHardwareBreakPoint64From32(system, args);
4124 case SvcId::GetDebugThreadParam: 4124 case SvcId::GetDebugThreadParam:
4125 return SvcWrap_GetDebugThreadParam64From32(system); 4125 return SvcWrap_GetDebugThreadParam64From32(system, args);
4126 case SvcId::GetSystemInfo: 4126 case SvcId::GetSystemInfo:
4127 return SvcWrap_GetSystemInfo64From32(system); 4127 return SvcWrap_GetSystemInfo64From32(system, args);
4128 case SvcId::CreatePort: 4128 case SvcId::CreatePort:
4129 return SvcWrap_CreatePort64From32(system); 4129 return SvcWrap_CreatePort64From32(system, args);
4130 case SvcId::ManageNamedPort: 4130 case SvcId::ManageNamedPort:
4131 return SvcWrap_ManageNamedPort64From32(system); 4131 return SvcWrap_ManageNamedPort64From32(system, args);
4132 case SvcId::ConnectToPort: 4132 case SvcId::ConnectToPort:
4133 return SvcWrap_ConnectToPort64From32(system); 4133 return SvcWrap_ConnectToPort64From32(system, args);
4134 case SvcId::SetProcessMemoryPermission: 4134 case SvcId::SetProcessMemoryPermission:
4135 return SvcWrap_SetProcessMemoryPermission64From32(system); 4135 return SvcWrap_SetProcessMemoryPermission64From32(system, args);
4136 case SvcId::MapProcessMemory: 4136 case SvcId::MapProcessMemory:
4137 return SvcWrap_MapProcessMemory64From32(system); 4137 return SvcWrap_MapProcessMemory64From32(system, args);
4138 case SvcId::UnmapProcessMemory: 4138 case SvcId::UnmapProcessMemory:
4139 return SvcWrap_UnmapProcessMemory64From32(system); 4139 return SvcWrap_UnmapProcessMemory64From32(system, args);
4140 case SvcId::QueryProcessMemory: 4140 case SvcId::QueryProcessMemory:
4141 return SvcWrap_QueryProcessMemory64From32(system); 4141 return SvcWrap_QueryProcessMemory64From32(system, args);
4142 case SvcId::MapProcessCodeMemory: 4142 case SvcId::MapProcessCodeMemory:
4143 return SvcWrap_MapProcessCodeMemory64From32(system); 4143 return SvcWrap_MapProcessCodeMemory64From32(system, args);
4144 case SvcId::UnmapProcessCodeMemory: 4144 case SvcId::UnmapProcessCodeMemory:
4145 return SvcWrap_UnmapProcessCodeMemory64From32(system); 4145 return SvcWrap_UnmapProcessCodeMemory64From32(system, args);
4146 case SvcId::CreateProcess: 4146 case SvcId::CreateProcess:
4147 return SvcWrap_CreateProcess64From32(system); 4147 return SvcWrap_CreateProcess64From32(system, args);
4148 case SvcId::StartProcess: 4148 case SvcId::StartProcess:
4149 return SvcWrap_StartProcess64From32(system); 4149 return SvcWrap_StartProcess64From32(system, args);
4150 case SvcId::TerminateProcess: 4150 case SvcId::TerminateProcess:
4151 return SvcWrap_TerminateProcess64From32(system); 4151 return SvcWrap_TerminateProcess64From32(system, args);
4152 case SvcId::GetProcessInfo: 4152 case SvcId::GetProcessInfo:
4153 return SvcWrap_GetProcessInfo64From32(system); 4153 return SvcWrap_GetProcessInfo64From32(system, args);
4154 case SvcId::CreateResourceLimit: 4154 case SvcId::CreateResourceLimit:
4155 return SvcWrap_CreateResourceLimit64From32(system); 4155 return SvcWrap_CreateResourceLimit64From32(system, args);
4156 case SvcId::SetResourceLimitLimitValue: 4156 case SvcId::SetResourceLimitLimitValue:
4157 return SvcWrap_SetResourceLimitLimitValue64From32(system); 4157 return SvcWrap_SetResourceLimitLimitValue64From32(system, args);
4158 case SvcId::CallSecureMonitor: 4158 case SvcId::CallSecureMonitor:
4159 return SvcWrap_CallSecureMonitor64From32(system); 4159 return SvcWrap_CallSecureMonitor64From32(system, args);
4160 case SvcId::MapInsecureMemory: 4160 case SvcId::MapInsecureMemory:
4161 return SvcWrap_MapInsecureMemory64From32(system); 4161 return SvcWrap_MapInsecureMemory64From32(system, args);
4162 case SvcId::UnmapInsecureMemory: 4162 case SvcId::UnmapInsecureMemory:
4163 return SvcWrap_UnmapInsecureMemory64From32(system); 4163 return SvcWrap_UnmapInsecureMemory64From32(system, args);
4164 default: 4164 default:
4165 LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm); 4165 LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm);
4166 break; 4166 break;
4167 } 4167 }
4168} 4168}
4169 4169
4170static void Call64(Core::System& system, u32 imm) { 4170static void Call64(Core::System& system, u32 imm, std::span<uint64_t, 8> args) {
4171 switch (static_cast<SvcId>(imm)) { 4171 switch (static_cast<SvcId>(imm)) {
4172 case SvcId::SetHeapSize: 4172 case SvcId::SetHeapSize:
4173 return SvcWrap_SetHeapSize64(system); 4173 return SvcWrap_SetHeapSize64(system, args);
4174 case SvcId::SetMemoryPermission: 4174 case SvcId::SetMemoryPermission:
4175 return SvcWrap_SetMemoryPermission64(system); 4175 return SvcWrap_SetMemoryPermission64(system, args);
4176 case SvcId::SetMemoryAttribute: 4176 case SvcId::SetMemoryAttribute:
4177 return SvcWrap_SetMemoryAttribute64(system); 4177 return SvcWrap_SetMemoryAttribute64(system, args);
4178 case SvcId::MapMemory: 4178 case SvcId::MapMemory:
4179 return SvcWrap_MapMemory64(system); 4179 return SvcWrap_MapMemory64(system, args);
4180 case SvcId::UnmapMemory: 4180 case SvcId::UnmapMemory:
4181 return SvcWrap_UnmapMemory64(system); 4181 return SvcWrap_UnmapMemory64(system, args);
4182 case SvcId::QueryMemory: 4182 case SvcId::QueryMemory:
4183 return SvcWrap_QueryMemory64(system); 4183 return SvcWrap_QueryMemory64(system, args);
4184 case SvcId::ExitProcess: 4184 case SvcId::ExitProcess:
4185 return SvcWrap_ExitProcess64(system); 4185 return SvcWrap_ExitProcess64(system, args);
4186 case SvcId::CreateThread: 4186 case SvcId::CreateThread:
4187 return SvcWrap_CreateThread64(system); 4187 return SvcWrap_CreateThread64(system, args);
4188 case SvcId::StartThread: 4188 case SvcId::StartThread:
4189 return SvcWrap_StartThread64(system); 4189 return SvcWrap_StartThread64(system, args);
4190 case SvcId::ExitThread: 4190 case SvcId::ExitThread:
4191 return SvcWrap_ExitThread64(system); 4191 return SvcWrap_ExitThread64(system, args);
4192 case SvcId::SleepThread: 4192 case SvcId::SleepThread:
4193 return SvcWrap_SleepThread64(system); 4193 return SvcWrap_SleepThread64(system, args);
4194 case SvcId::GetThreadPriority: 4194 case SvcId::GetThreadPriority:
4195 return SvcWrap_GetThreadPriority64(system); 4195 return SvcWrap_GetThreadPriority64(system, args);
4196 case SvcId::SetThreadPriority: 4196 case SvcId::SetThreadPriority:
4197 return SvcWrap_SetThreadPriority64(system); 4197 return SvcWrap_SetThreadPriority64(system, args);
4198 case SvcId::GetThreadCoreMask: 4198 case SvcId::GetThreadCoreMask:
4199 return SvcWrap_GetThreadCoreMask64(system); 4199 return SvcWrap_GetThreadCoreMask64(system, args);
4200 case SvcId::SetThreadCoreMask: 4200 case SvcId::SetThreadCoreMask:
4201 return SvcWrap_SetThreadCoreMask64(system); 4201 return SvcWrap_SetThreadCoreMask64(system, args);
4202 case SvcId::GetCurrentProcessorNumber: 4202 case SvcId::GetCurrentProcessorNumber:
4203 return SvcWrap_GetCurrentProcessorNumber64(system); 4203 return SvcWrap_GetCurrentProcessorNumber64(system, args);
4204 case SvcId::SignalEvent: 4204 case SvcId::SignalEvent:
4205 return SvcWrap_SignalEvent64(system); 4205 return SvcWrap_SignalEvent64(system, args);
4206 case SvcId::ClearEvent: 4206 case SvcId::ClearEvent:
4207 return SvcWrap_ClearEvent64(system); 4207 return SvcWrap_ClearEvent64(system, args);
4208 case SvcId::MapSharedMemory: 4208 case SvcId::MapSharedMemory:
4209 return SvcWrap_MapSharedMemory64(system); 4209 return SvcWrap_MapSharedMemory64(system, args);
4210 case SvcId::UnmapSharedMemory: 4210 case SvcId::UnmapSharedMemory:
4211 return SvcWrap_UnmapSharedMemory64(system); 4211 return SvcWrap_UnmapSharedMemory64(system, args);
4212 case SvcId::CreateTransferMemory: 4212 case SvcId::CreateTransferMemory:
4213 return SvcWrap_CreateTransferMemory64(system); 4213 return SvcWrap_CreateTransferMemory64(system, args);
4214 case SvcId::CloseHandle: 4214 case SvcId::CloseHandle:
4215 return SvcWrap_CloseHandle64(system); 4215 return SvcWrap_CloseHandle64(system, args);
4216 case SvcId::ResetSignal: 4216 case SvcId::ResetSignal:
4217 return SvcWrap_ResetSignal64(system); 4217 return SvcWrap_ResetSignal64(system, args);
4218 case SvcId::WaitSynchronization: 4218 case SvcId::WaitSynchronization:
4219 return SvcWrap_WaitSynchronization64(system); 4219 return SvcWrap_WaitSynchronization64(system, args);
4220 case SvcId::CancelSynchronization: 4220 case SvcId::CancelSynchronization:
4221 return SvcWrap_CancelSynchronization64(system); 4221 return SvcWrap_CancelSynchronization64(system, args);
4222 case SvcId::ArbitrateLock: 4222 case SvcId::ArbitrateLock:
4223 return SvcWrap_ArbitrateLock64(system); 4223 return SvcWrap_ArbitrateLock64(system, args);
4224 case SvcId::ArbitrateUnlock: 4224 case SvcId::ArbitrateUnlock:
4225 return SvcWrap_ArbitrateUnlock64(system); 4225 return SvcWrap_ArbitrateUnlock64(system, args);
4226 case SvcId::WaitProcessWideKeyAtomic: 4226 case SvcId::WaitProcessWideKeyAtomic:
4227 return SvcWrap_WaitProcessWideKeyAtomic64(system); 4227 return SvcWrap_WaitProcessWideKeyAtomic64(system, args);
4228 case SvcId::SignalProcessWideKey: 4228 case SvcId::SignalProcessWideKey:
4229 return SvcWrap_SignalProcessWideKey64(system); 4229 return SvcWrap_SignalProcessWideKey64(system, args);
4230 case SvcId::GetSystemTick: 4230 case SvcId::GetSystemTick:
4231 return SvcWrap_GetSystemTick64(system); 4231 return SvcWrap_GetSystemTick64(system, args);
4232 case SvcId::ConnectToNamedPort: 4232 case SvcId::ConnectToNamedPort:
4233 return SvcWrap_ConnectToNamedPort64(system); 4233 return SvcWrap_ConnectToNamedPort64(system, args);
4234 case SvcId::SendSyncRequestLight: 4234 case SvcId::SendSyncRequestLight:
4235 return SvcWrap_SendSyncRequestLight64(system); 4235 return SvcWrap_SendSyncRequestLight64(system, args);
4236 case SvcId::SendSyncRequest: 4236 case SvcId::SendSyncRequest:
4237 return SvcWrap_SendSyncRequest64(system); 4237 return SvcWrap_SendSyncRequest64(system, args);
4238 case SvcId::SendSyncRequestWithUserBuffer: 4238 case SvcId::SendSyncRequestWithUserBuffer:
4239 return SvcWrap_SendSyncRequestWithUserBuffer64(system); 4239 return SvcWrap_SendSyncRequestWithUserBuffer64(system, args);
4240 case SvcId::SendAsyncRequestWithUserBuffer: 4240 case SvcId::SendAsyncRequestWithUserBuffer:
4241 return SvcWrap_SendAsyncRequestWithUserBuffer64(system); 4241 return SvcWrap_SendAsyncRequestWithUserBuffer64(system, args);
4242 case SvcId::GetProcessId: 4242 case SvcId::GetProcessId:
4243 return SvcWrap_GetProcessId64(system); 4243 return SvcWrap_GetProcessId64(system, args);
4244 case SvcId::GetThreadId: 4244 case SvcId::GetThreadId:
4245 return SvcWrap_GetThreadId64(system); 4245 return SvcWrap_GetThreadId64(system, args);
4246 case SvcId::Break: 4246 case SvcId::Break:
4247 return SvcWrap_Break64(system); 4247 return SvcWrap_Break64(system, args);
4248 case SvcId::OutputDebugString: 4248 case SvcId::OutputDebugString:
4249 return SvcWrap_OutputDebugString64(system); 4249 return SvcWrap_OutputDebugString64(system, args);
4250 case SvcId::ReturnFromException: 4250 case SvcId::ReturnFromException:
4251 return SvcWrap_ReturnFromException64(system); 4251 return SvcWrap_ReturnFromException64(system, args);
4252 case SvcId::GetInfo: 4252 case SvcId::GetInfo:
4253 return SvcWrap_GetInfo64(system); 4253 return SvcWrap_GetInfo64(system, args);
4254 case SvcId::FlushEntireDataCache: 4254 case SvcId::FlushEntireDataCache:
4255 return SvcWrap_FlushEntireDataCache64(system); 4255 return SvcWrap_FlushEntireDataCache64(system, args);
4256 case SvcId::FlushDataCache: 4256 case SvcId::FlushDataCache:
4257 return SvcWrap_FlushDataCache64(system); 4257 return SvcWrap_FlushDataCache64(system, args);
4258 case SvcId::MapPhysicalMemory: 4258 case SvcId::MapPhysicalMemory:
4259 return SvcWrap_MapPhysicalMemory64(system); 4259 return SvcWrap_MapPhysicalMemory64(system, args);
4260 case SvcId::UnmapPhysicalMemory: 4260 case SvcId::UnmapPhysicalMemory:
4261 return SvcWrap_UnmapPhysicalMemory64(system); 4261 return SvcWrap_UnmapPhysicalMemory64(system, args);
4262 case SvcId::GetDebugFutureThreadInfo: 4262 case SvcId::GetDebugFutureThreadInfo:
4263 return SvcWrap_GetDebugFutureThreadInfo64(system); 4263 return SvcWrap_GetDebugFutureThreadInfo64(system, args);
4264 case SvcId::GetLastThreadInfo: 4264 case SvcId::GetLastThreadInfo:
4265 return SvcWrap_GetLastThreadInfo64(system); 4265 return SvcWrap_GetLastThreadInfo64(system, args);
4266 case SvcId::GetResourceLimitLimitValue: 4266 case SvcId::GetResourceLimitLimitValue:
4267 return SvcWrap_GetResourceLimitLimitValue64(system); 4267 return SvcWrap_GetResourceLimitLimitValue64(system, args);
4268 case SvcId::GetResourceLimitCurrentValue: 4268 case SvcId::GetResourceLimitCurrentValue:
4269 return SvcWrap_GetResourceLimitCurrentValue64(system); 4269 return SvcWrap_GetResourceLimitCurrentValue64(system, args);
4270 case SvcId::SetThreadActivity: 4270 case SvcId::SetThreadActivity:
4271 return SvcWrap_SetThreadActivity64(system); 4271 return SvcWrap_SetThreadActivity64(system, args);
4272 case SvcId::GetThreadContext3: 4272 case SvcId::GetThreadContext3:
4273 return SvcWrap_GetThreadContext364(system); 4273 return SvcWrap_GetThreadContext364(system, args);
4274 case SvcId::WaitForAddress: 4274 case SvcId::WaitForAddress:
4275 return SvcWrap_WaitForAddress64(system); 4275 return SvcWrap_WaitForAddress64(system, args);
4276 case SvcId::SignalToAddress: 4276 case SvcId::SignalToAddress:
4277 return SvcWrap_SignalToAddress64(system); 4277 return SvcWrap_SignalToAddress64(system, args);
4278 case SvcId::SynchronizePreemptionState: 4278 case SvcId::SynchronizePreemptionState:
4279 return SvcWrap_SynchronizePreemptionState64(system); 4279 return SvcWrap_SynchronizePreemptionState64(system, args);
4280 case SvcId::GetResourceLimitPeakValue: 4280 case SvcId::GetResourceLimitPeakValue:
4281 return SvcWrap_GetResourceLimitPeakValue64(system); 4281 return SvcWrap_GetResourceLimitPeakValue64(system, args);
4282 case SvcId::CreateIoPool: 4282 case SvcId::CreateIoPool:
4283 return SvcWrap_CreateIoPool64(system); 4283 return SvcWrap_CreateIoPool64(system, args);
4284 case SvcId::CreateIoRegion: 4284 case SvcId::CreateIoRegion:
4285 return SvcWrap_CreateIoRegion64(system); 4285 return SvcWrap_CreateIoRegion64(system, args);
4286 case SvcId::KernelDebug: 4286 case SvcId::KernelDebug:
4287 return SvcWrap_KernelDebug64(system); 4287 return SvcWrap_KernelDebug64(system, args);
4288 case SvcId::ChangeKernelTraceState: 4288 case SvcId::ChangeKernelTraceState:
4289 return SvcWrap_ChangeKernelTraceState64(system); 4289 return SvcWrap_ChangeKernelTraceState64(system, args);
4290 case SvcId::CreateSession: 4290 case SvcId::CreateSession:
4291 return SvcWrap_CreateSession64(system); 4291 return SvcWrap_CreateSession64(system, args);
4292 case SvcId::AcceptSession: 4292 case SvcId::AcceptSession:
4293 return SvcWrap_AcceptSession64(system); 4293 return SvcWrap_AcceptSession64(system, args);
4294 case SvcId::ReplyAndReceiveLight: 4294 case SvcId::ReplyAndReceiveLight:
4295 return SvcWrap_ReplyAndReceiveLight64(system); 4295 return SvcWrap_ReplyAndReceiveLight64(system, args);
4296 case SvcId::ReplyAndReceive: 4296 case SvcId::ReplyAndReceive:
4297 return SvcWrap_ReplyAndReceive64(system); 4297 return SvcWrap_ReplyAndReceive64(system, args);
4298 case SvcId::ReplyAndReceiveWithUserBuffer: 4298 case SvcId::ReplyAndReceiveWithUserBuffer:
4299 return SvcWrap_ReplyAndReceiveWithUserBuffer64(system); 4299 return SvcWrap_ReplyAndReceiveWithUserBuffer64(system, args);
4300 case SvcId::CreateEvent: 4300 case SvcId::CreateEvent:
4301 return SvcWrap_CreateEvent64(system); 4301 return SvcWrap_CreateEvent64(system, args);
4302 case SvcId::MapIoRegion: 4302 case SvcId::MapIoRegion:
4303 return SvcWrap_MapIoRegion64(system); 4303 return SvcWrap_MapIoRegion64(system, args);
4304 case SvcId::UnmapIoRegion: 4304 case SvcId::UnmapIoRegion:
4305 return SvcWrap_UnmapIoRegion64(system); 4305 return SvcWrap_UnmapIoRegion64(system, args);
4306 case SvcId::MapPhysicalMemoryUnsafe: 4306 case SvcId::MapPhysicalMemoryUnsafe:
4307 return SvcWrap_MapPhysicalMemoryUnsafe64(system); 4307 return SvcWrap_MapPhysicalMemoryUnsafe64(system, args);
4308 case SvcId::UnmapPhysicalMemoryUnsafe: 4308 case SvcId::UnmapPhysicalMemoryUnsafe:
4309 return SvcWrap_UnmapPhysicalMemoryUnsafe64(system); 4309 return SvcWrap_UnmapPhysicalMemoryUnsafe64(system, args);
4310 case SvcId::SetUnsafeLimit: 4310 case SvcId::SetUnsafeLimit:
4311 return SvcWrap_SetUnsafeLimit64(system); 4311 return SvcWrap_SetUnsafeLimit64(system, args);
4312 case SvcId::CreateCodeMemory: 4312 case SvcId::CreateCodeMemory:
4313 return SvcWrap_CreateCodeMemory64(system); 4313 return SvcWrap_CreateCodeMemory64(system, args);
4314 case SvcId::ControlCodeMemory: 4314 case SvcId::ControlCodeMemory:
4315 return SvcWrap_ControlCodeMemory64(system); 4315 return SvcWrap_ControlCodeMemory64(system, args);
4316 case SvcId::SleepSystem: 4316 case SvcId::SleepSystem:
4317 return SvcWrap_SleepSystem64(system); 4317 return SvcWrap_SleepSystem64(system, args);
4318 case SvcId::ReadWriteRegister: 4318 case SvcId::ReadWriteRegister:
4319 return SvcWrap_ReadWriteRegister64(system); 4319 return SvcWrap_ReadWriteRegister64(system, args);
4320 case SvcId::SetProcessActivity: 4320 case SvcId::SetProcessActivity:
4321 return SvcWrap_SetProcessActivity64(system); 4321 return SvcWrap_SetProcessActivity64(system, args);
4322 case SvcId::CreateSharedMemory: 4322 case SvcId::CreateSharedMemory:
4323 return SvcWrap_CreateSharedMemory64(system); 4323 return SvcWrap_CreateSharedMemory64(system, args);
4324 case SvcId::MapTransferMemory: 4324 case SvcId::MapTransferMemory:
4325 return SvcWrap_MapTransferMemory64(system); 4325 return SvcWrap_MapTransferMemory64(system, args);
4326 case SvcId::UnmapTransferMemory: 4326 case SvcId::UnmapTransferMemory:
4327 return SvcWrap_UnmapTransferMemory64(system); 4327 return SvcWrap_UnmapTransferMemory64(system, args);
4328 case SvcId::CreateInterruptEvent: 4328 case SvcId::CreateInterruptEvent:
4329 return SvcWrap_CreateInterruptEvent64(system); 4329 return SvcWrap_CreateInterruptEvent64(system, args);
4330 case SvcId::QueryPhysicalAddress: 4330 case SvcId::QueryPhysicalAddress:
4331 return SvcWrap_QueryPhysicalAddress64(system); 4331 return SvcWrap_QueryPhysicalAddress64(system, args);
4332 case SvcId::QueryIoMapping: 4332 case SvcId::QueryIoMapping:
4333 return SvcWrap_QueryIoMapping64(system); 4333 return SvcWrap_QueryIoMapping64(system, args);
4334 case SvcId::CreateDeviceAddressSpace: 4334 case SvcId::CreateDeviceAddressSpace:
4335 return SvcWrap_CreateDeviceAddressSpace64(system); 4335 return SvcWrap_CreateDeviceAddressSpace64(system, args);
4336 case SvcId::AttachDeviceAddressSpace: 4336 case SvcId::AttachDeviceAddressSpace:
4337 return SvcWrap_AttachDeviceAddressSpace64(system); 4337 return SvcWrap_AttachDeviceAddressSpace64(system, args);
4338 case SvcId::DetachDeviceAddressSpace: 4338 case SvcId::DetachDeviceAddressSpace:
4339 return SvcWrap_DetachDeviceAddressSpace64(system); 4339 return SvcWrap_DetachDeviceAddressSpace64(system, args);
4340 case SvcId::MapDeviceAddressSpaceByForce: 4340 case SvcId::MapDeviceAddressSpaceByForce:
4341 return SvcWrap_MapDeviceAddressSpaceByForce64(system); 4341 return SvcWrap_MapDeviceAddressSpaceByForce64(system, args);
4342 case SvcId::MapDeviceAddressSpaceAligned: 4342 case SvcId::MapDeviceAddressSpaceAligned:
4343 return SvcWrap_MapDeviceAddressSpaceAligned64(system); 4343 return SvcWrap_MapDeviceAddressSpaceAligned64(system, args);
4344 case SvcId::UnmapDeviceAddressSpace: 4344 case SvcId::UnmapDeviceAddressSpace:
4345 return SvcWrap_UnmapDeviceAddressSpace64(system); 4345 return SvcWrap_UnmapDeviceAddressSpace64(system, args);
4346 case SvcId::InvalidateProcessDataCache: 4346 case SvcId::InvalidateProcessDataCache:
4347 return SvcWrap_InvalidateProcessDataCache64(system); 4347 return SvcWrap_InvalidateProcessDataCache64(system, args);
4348 case SvcId::StoreProcessDataCache: 4348 case SvcId::StoreProcessDataCache:
4349 return SvcWrap_StoreProcessDataCache64(system); 4349 return SvcWrap_StoreProcessDataCache64(system, args);
4350 case SvcId::FlushProcessDataCache: 4350 case SvcId::FlushProcessDataCache:
4351 return SvcWrap_FlushProcessDataCache64(system); 4351 return SvcWrap_FlushProcessDataCache64(system, args);
4352 case SvcId::DebugActiveProcess: 4352 case SvcId::DebugActiveProcess:
4353 return SvcWrap_DebugActiveProcess64(system); 4353 return SvcWrap_DebugActiveProcess64(system, args);
4354 case SvcId::BreakDebugProcess: 4354 case SvcId::BreakDebugProcess:
4355 return SvcWrap_BreakDebugProcess64(system); 4355 return SvcWrap_BreakDebugProcess64(system, args);
4356 case SvcId::TerminateDebugProcess: 4356 case SvcId::TerminateDebugProcess:
4357 return SvcWrap_TerminateDebugProcess64(system); 4357 return SvcWrap_TerminateDebugProcess64(system, args);
4358 case SvcId::GetDebugEvent: 4358 case SvcId::GetDebugEvent:
4359 return SvcWrap_GetDebugEvent64(system); 4359 return SvcWrap_GetDebugEvent64(system, args);
4360 case SvcId::ContinueDebugEvent: 4360 case SvcId::ContinueDebugEvent:
4361 return SvcWrap_ContinueDebugEvent64(system); 4361 return SvcWrap_ContinueDebugEvent64(system, args);
4362 case SvcId::GetProcessList: 4362 case SvcId::GetProcessList:
4363 return SvcWrap_GetProcessList64(system); 4363 return SvcWrap_GetProcessList64(system, args);
4364 case SvcId::GetThreadList: 4364 case SvcId::GetThreadList:
4365 return SvcWrap_GetThreadList64(system); 4365 return SvcWrap_GetThreadList64(system, args);
4366 case SvcId::GetDebugThreadContext: 4366 case SvcId::GetDebugThreadContext:
4367 return SvcWrap_GetDebugThreadContext64(system); 4367 return SvcWrap_GetDebugThreadContext64(system, args);
4368 case SvcId::SetDebugThreadContext: 4368 case SvcId::SetDebugThreadContext:
4369 return SvcWrap_SetDebugThreadContext64(system); 4369 return SvcWrap_SetDebugThreadContext64(system, args);
4370 case SvcId::QueryDebugProcessMemory: 4370 case SvcId::QueryDebugProcessMemory:
4371 return SvcWrap_QueryDebugProcessMemory64(system); 4371 return SvcWrap_QueryDebugProcessMemory64(system, args);
4372 case SvcId::ReadDebugProcessMemory: 4372 case SvcId::ReadDebugProcessMemory:
4373 return SvcWrap_ReadDebugProcessMemory64(system); 4373 return SvcWrap_ReadDebugProcessMemory64(system, args);
4374 case SvcId::WriteDebugProcessMemory: 4374 case SvcId::WriteDebugProcessMemory:
4375 return SvcWrap_WriteDebugProcessMemory64(system); 4375 return SvcWrap_WriteDebugProcessMemory64(system, args);
4376 case SvcId::SetHardwareBreakPoint: 4376 case SvcId::SetHardwareBreakPoint:
4377 return SvcWrap_SetHardwareBreakPoint64(system); 4377 return SvcWrap_SetHardwareBreakPoint64(system, args);
4378 case SvcId::GetDebugThreadParam: 4378 case SvcId::GetDebugThreadParam:
4379 return SvcWrap_GetDebugThreadParam64(system); 4379 return SvcWrap_GetDebugThreadParam64(system, args);
4380 case SvcId::GetSystemInfo: 4380 case SvcId::GetSystemInfo:
4381 return SvcWrap_GetSystemInfo64(system); 4381 return SvcWrap_GetSystemInfo64(system, args);
4382 case SvcId::CreatePort: 4382 case SvcId::CreatePort:
4383 return SvcWrap_CreatePort64(system); 4383 return SvcWrap_CreatePort64(system, args);
4384 case SvcId::ManageNamedPort: 4384 case SvcId::ManageNamedPort:
4385 return SvcWrap_ManageNamedPort64(system); 4385 return SvcWrap_ManageNamedPort64(system, args);
4386 case SvcId::ConnectToPort: 4386 case SvcId::ConnectToPort:
4387 return SvcWrap_ConnectToPort64(system); 4387 return SvcWrap_ConnectToPort64(system, args);
4388 case SvcId::SetProcessMemoryPermission: 4388 case SvcId::SetProcessMemoryPermission:
4389 return SvcWrap_SetProcessMemoryPermission64(system); 4389 return SvcWrap_SetProcessMemoryPermission64(system, args);
4390 case SvcId::MapProcessMemory: 4390 case SvcId::MapProcessMemory:
4391 return SvcWrap_MapProcessMemory64(system); 4391 return SvcWrap_MapProcessMemory64(system, args);
4392 case SvcId::UnmapProcessMemory: 4392 case SvcId::UnmapProcessMemory:
4393 return SvcWrap_UnmapProcessMemory64(system); 4393 return SvcWrap_UnmapProcessMemory64(system, args);
4394 case SvcId::QueryProcessMemory: 4394 case SvcId::QueryProcessMemory:
4395 return SvcWrap_QueryProcessMemory64(system); 4395 return SvcWrap_QueryProcessMemory64(system, args);
4396 case SvcId::MapProcessCodeMemory: 4396 case SvcId::MapProcessCodeMemory:
4397 return SvcWrap_MapProcessCodeMemory64(system); 4397 return SvcWrap_MapProcessCodeMemory64(system, args);
4398 case SvcId::UnmapProcessCodeMemory: 4398 case SvcId::UnmapProcessCodeMemory:
4399 return SvcWrap_UnmapProcessCodeMemory64(system); 4399 return SvcWrap_UnmapProcessCodeMemory64(system, args);
4400 case SvcId::CreateProcess: 4400 case SvcId::CreateProcess:
4401 return SvcWrap_CreateProcess64(system); 4401 return SvcWrap_CreateProcess64(system, args);
4402 case SvcId::StartProcess: 4402 case SvcId::StartProcess:
4403 return SvcWrap_StartProcess64(system); 4403 return SvcWrap_StartProcess64(system, args);
4404 case SvcId::TerminateProcess: 4404 case SvcId::TerminateProcess:
4405 return SvcWrap_TerminateProcess64(system); 4405 return SvcWrap_TerminateProcess64(system, args);
4406 case SvcId::GetProcessInfo: 4406 case SvcId::GetProcessInfo:
4407 return SvcWrap_GetProcessInfo64(system); 4407 return SvcWrap_GetProcessInfo64(system, args);
4408 case SvcId::CreateResourceLimit: 4408 case SvcId::CreateResourceLimit:
4409 return SvcWrap_CreateResourceLimit64(system); 4409 return SvcWrap_CreateResourceLimit64(system, args);
4410 case SvcId::SetResourceLimitLimitValue: 4410 case SvcId::SetResourceLimitLimitValue:
4411 return SvcWrap_SetResourceLimitLimitValue64(system); 4411 return SvcWrap_SetResourceLimitLimitValue64(system, args);
4412 case SvcId::CallSecureMonitor: 4412 case SvcId::CallSecureMonitor:
4413 return SvcWrap_CallSecureMonitor64(system); 4413 return SvcWrap_CallSecureMonitor64(system, args);
4414 case SvcId::MapInsecureMemory: 4414 case SvcId::MapInsecureMemory:
4415 return SvcWrap_MapInsecureMemory64(system); 4415 return SvcWrap_MapInsecureMemory64(system, args);
4416 case SvcId::UnmapInsecureMemory: 4416 case SvcId::UnmapInsecureMemory:
4417 return SvcWrap_UnmapInsecureMemory64(system); 4417 return SvcWrap_UnmapInsecureMemory64(system, args);
4418 default: 4418 default:
4419 LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm); 4419 LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm);
4420 break; 4420 break;
@@ -4424,15 +4424,20 @@ static void Call64(Core::System& system, u32 imm) {
4424 4424
4425void Call(Core::System& system, u32 imm) { 4425void Call(Core::System& system, u32 imm) {
4426 auto& kernel = system.Kernel(); 4426 auto& kernel = system.Kernel();
4427 auto& process = GetCurrentProcess(kernel);
4428
4429 std::array<uint64_t, 8> args;
4430 kernel.CurrentPhysicalCore().SaveSvcArguments(process, args);
4427 kernel.EnterSVCProfile(); 4431 kernel.EnterSVCProfile();
4428 4432
4429 if (GetCurrentProcess(system.Kernel()).Is64Bit()) { 4433 if (process.Is64Bit()) {
4430 Call64(system, imm); 4434 Call64(system, imm, args);
4431 } else { 4435 } else {
4432 Call32(system, imm); 4436 Call32(system, imm, args);
4433 } 4437 }
4434 4438
4435 kernel.ExitSVCProfile(); 4439 kernel.ExitSVCProfile();
4440 kernel.CurrentPhysicalCore().LoadSvcArguments(process, args);
4436} 4441}
4437 4442
4438} // namespace Kernel::Svc 4443} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h
index ac4696008..828f39611 100644
--- a/src/core/hle/kernel/svc.h
+++ b/src/core/hle/kernel/svc.h
@@ -9,6 +9,8 @@ namespace Core {
9class System; 9class System;
10} 10}
11 11
12#include <span>
13
12#include "common/common_types.h" 14#include "common/common_types.h"
13#include "core/hle/kernel/svc_types.h" 15#include "core/hle/kernel/svc_types.h"
14#include "core/hle/result.h" 16#include "core/hle/result.h"
@@ -520,15 +522,15 @@ void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArgumen
520void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args); 522void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
521 523
522// Defined in svc_light_ipc.cpp. 524// Defined in svc_light_ipc.cpp.
523void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system); 525void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args);
524void SvcWrap_ReplyAndReceiveLight64(Core::System& system); 526void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args);
525 527
526void SvcWrap_SendSyncRequestLight64From32(Core::System& system); 528void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args);
527void SvcWrap_SendSyncRequestLight64(Core::System& system); 529void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args);
528 530
529// Defined in svc_secure_monitor_call.cpp. 531// Defined in svc_secure_monitor_call.cpp.
530void SvcWrap_CallSecureMonitor64From32(Core::System& system); 532void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args);
531void SvcWrap_CallSecureMonitor64(Core::System& system); 533void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args);
532 534
533// Perform a supervisor call by index. 535// Perform a supervisor call by index.
534void Call(Core::System& system, u32 imm); 536void Call(Core::System& system, u32 imm);
diff --git a/src/core/hle/kernel/svc/svc_exception.cpp b/src/core/hle/kernel/svc/svc_exception.cpp
index c581c086b..47b756828 100644
--- a/src/core/hle/kernel/svc/svc_exception.cpp
+++ b/src/core/hle/kernel/svc/svc_exception.cpp
@@ -103,9 +103,7 @@ void Break(Core::System& system, BreakReason reason, u64 info1, u64 info2) {
103 103
104 handle_debug_buffer(info1, info2); 104 handle_debug_buffer(info1, info2);
105 105
106 auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); 106 system.CurrentPhysicalCore().LogBacktrace();
107 const auto thread_processor_id = current_thread->GetActiveCore();
108 system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace();
109 } 107 }
110 108
111 const bool is_hbl = GetCurrentProcess(system.Kernel()).IsHbl(); 109 const bool is_hbl = GetCurrentProcess(system.Kernel()).IsHbl();
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp
index 6b5e1cb8d..47a3e7bb0 100644
--- a/src/core/hle/kernel/svc/svc_ipc.cpp
+++ b/src/core/hle/kernel/svc/svc_ipc.cpp
@@ -7,59 +7,127 @@
7#include "core/hle/kernel/k_client_session.h" 7#include "core/hle/kernel/k_client_session.h"
8#include "core/hle/kernel/k_hardware_timer.h" 8#include "core/hle/kernel/k_hardware_timer.h"
9#include "core/hle/kernel/k_process.h" 9#include "core/hle/kernel/k_process.h"
10#include "core/hle/kernel/k_scoped_resource_reservation.h"
10#include "core/hle/kernel/k_server_session.h" 11#include "core/hle/kernel/k_server_session.h"
12#include "core/hle/kernel/k_session.h"
11#include "core/hle/kernel/svc.h" 13#include "core/hle/kernel/svc.h"
12#include "core/hle/kernel/svc_results.h" 14#include "core/hle/kernel/svc_results.h"
13 15
14namespace Kernel::Svc { 16namespace Kernel::Svc {
15 17
16/// Makes a blocking IPC call to a service. 18namespace {
17Result SendSyncRequest(Core::System& system, Handle handle) { 19
18 // Get the client session from its handle. 20Result SendSyncRequestImpl(KernelCore& kernel, uintptr_t message, size_t buffer_size,
21 Handle session_handle) {
22 // Get the client session.
19 KScopedAutoObject session = 23 KScopedAutoObject session =
20 GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KClientSession>(handle); 24 GetCurrentProcess(kernel).GetHandleTable().GetObject<KClientSession>(session_handle);
21 R_UNLESS(session.IsNotNull(), ResultInvalidHandle); 25 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
22 26
23 LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle); 27 // Get the parent, and persist a reference to it until we're done.
28 KScopedAutoObject parent = session->GetParent();
29 ASSERT(parent.IsNotNull());
24 30
25 R_RETURN(session->SendSyncRequest()); 31 // Send the request.
32 R_RETURN(session->SendSyncRequest(message, buffer_size));
26} 33}
27 34
28Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer, 35Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t message,
29 uint64_t message_buffer_size, Handle session_handle) { 36 size_t buffer_size, KPhysicalAddress message_paddr,
30 UNIMPLEMENTED(); 37 KSynchronizationObject** objs, int32_t num_objects, Handle reply_target,
31 R_THROW(ResultNotImplemented); 38 int64_t timeout_ns) {
32} 39 // Reply to the target, if one is specified.
40 if (reply_target != InvalidHandle) {
41 KScopedAutoObject session =
42 GetCurrentProcess(kernel).GetHandleTable().GetObject<KServerSession>(reply_target);
43 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
33 44
34Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, 45 // If we fail to reply, we want to set the output index to -1.
35 uint64_t message_buffer, uint64_t message_buffer_size, 46 ON_RESULT_FAILURE {
36 Handle session_handle) { 47 *out_index = -1;
37 UNIMPLEMENTED(); 48 };
38 R_THROW(ResultNotImplemented); 49
50 // Send the reply.
51 R_TRY(session->SendReply());
52 // R_TRY(session->SendReply(message, buffer_size, message_paddr));
53 }
54
55 // Receive a message.
56 {
57 // Convert the timeout from nanoseconds to ticks.
58 // NOTE: Nintendo does not use this conversion logic in WaitSynchronization...
59 s64 timeout;
60 if (timeout_ns > 0) {
61 const s64 offset_tick(timeout_ns);
62 if (offset_tick > 0) {
63 timeout = kernel.HardwareTimer().GetTick() + offset_tick + 2;
64 if (timeout <= 0) {
65 timeout = std::numeric_limits<s64>::max();
66 }
67 } else {
68 timeout = std::numeric_limits<s64>::max();
69 }
70 } else {
71 timeout = timeout_ns;
72 }
73
74 // Wait for a message.
75 while (true) {
76 // Wait for an object.
77 s32 index;
78 Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs,
79 num_objects, timeout);
80 if (ResultTimedOut == result) {
81 R_THROW(result);
82 }
83
84 // Receive the request.
85 if (R_SUCCEEDED(result)) {
86 KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
87 if (session != nullptr) {
88 // result = session->ReceiveRequest(message, buffer_size, message_paddr);
89 result = session->ReceiveRequest();
90 if (ResultNotFound == result) {
91 continue;
92 }
93 }
94 }
95
96 *out_index = index;
97 R_RETURN(result);
98 }
99 }
39} 100}
40 101
41Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles, 102Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t message,
42 Handle reply_target, s64 timeout_ns) { 103 size_t buffer_size, KPhysicalAddress message_paddr,
104 KProcessAddress user_handles, int32_t num_handles, Handle reply_target,
105 int64_t timeout_ns) {
43 // Ensure number of handles is valid. 106 // Ensure number of handles is valid.
44 R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); 107 R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange);
45 108
46 // Get the synchronization context. 109 // Get the synchronization context.
47 auto& kernel = system.Kernel(); 110 auto& process = GetCurrentProcess(kernel);
48 auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); 111 auto& thread = GetCurrentThread(kernel);
49 auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer(); 112 auto& handle_table = process.GetHandleTable();
50 auto handles = GetCurrentThread(kernel).GetHandleBuffer(); 113 KSynchronizationObject** objs = thread.GetSynchronizationObjectBuffer().data();
114 Handle* handles = thread.GetHandleBuffer().data();
51 115
52 // Copy user handles. 116 // Copy user handles.
53 if (num_handles > 0) { 117 if (num_handles > 0) {
54 // Get the handles. 118 // Ensure that we can try to get the handles.
55 R_UNLESS(GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), 119 R_UNLESS(process.GetPageTable().Contains(user_handles, num_handles * sizeof(Handle)),
56 sizeof(Handle) * num_handles),
57 ResultInvalidPointer); 120 ResultInvalidPointer);
58 121
122 // Get the handles
123 R_UNLESS(
124 GetCurrentMemory(kernel).ReadBlock(user_handles, handles, sizeof(Handle) * num_handles),
125 ResultInvalidPointer);
126
59 // Convert the handles to objects. 127 // Convert the handles to objects.
60 R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>( 128 R_UNLESS(
61 objs.data(), handles.data(), num_handles), 129 handle_table.GetMultipleObjects<KSynchronizationObject>(objs, handles, num_handles),
62 ResultInvalidHandle); 130 ResultInvalidHandle);
63 } 131 }
64 132
65 // Ensure handles are closed when we're done. 133 // Ensure handles are closed when we're done.
@@ -69,69 +137,135 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad
69 } 137 }
70 }); 138 });
71 139
72 // Reply to the target, if one is specified. 140 R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs,
73 if (reply_target != InvalidHandle) { 141 num_handles, reply_target, timeout_ns));
74 KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target); 142}
75 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
76 143
77 // If we fail to reply, we want to set the output index to -1. 144} // namespace
145
146/// Makes a blocking IPC call to a service.
147Result SendSyncRequest(Core::System& system, Handle session_handle) {
148 R_RETURN(SendSyncRequestImpl(system.Kernel(), 0, 0, session_handle));
149}
150
151Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message, uint64_t buffer_size,
152 Handle session_handle) {
153 auto& kernel = system.Kernel();
154
155 // Validate that the message buffer is page aligned and does not overflow.
156 R_UNLESS(Common::IsAligned(message, PageSize), ResultInvalidAddress);
157 R_UNLESS(buffer_size > 0, ResultInvalidSize);
158 R_UNLESS(Common::IsAligned(buffer_size, PageSize), ResultInvalidSize);
159 R_UNLESS(message < message + buffer_size, ResultInvalidCurrentMemory);
160
161 // Get the process page table.
162 auto& page_table = GetCurrentProcess(kernel).GetPageTable();
163
164 // Lock the message buffer.
165 R_TRY(page_table.LockForIpcUserBuffer(nullptr, message, buffer_size));
166
167 {
168 // If we fail to send the message, unlock the message buffer.
78 ON_RESULT_FAILURE { 169 ON_RESULT_FAILURE {
79 *out_index = -1; 170 page_table.UnlockForIpcUserBuffer(message, buffer_size);
80 }; 171 };
81 172
82 // Send the reply. 173 // Send the request.
83 R_TRY(session->SendReply()); 174 ASSERT(message != 0);
175 R_TRY(SendSyncRequestImpl(kernel, message, buffer_size, session_handle));
84 } 176 }
85 177
86 // Convert the timeout from nanoseconds to ticks. 178 // We successfully processed, so try to unlock the message buffer.
87 // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... 179 R_RETURN(page_table.UnlockForIpcUserBuffer(message, buffer_size));
88 s64 timeout; 180}
89 if (timeout_ns > 0) {
90 const s64 offset_tick(timeout_ns);
91 if (offset_tick > 0) {
92 timeout = kernel.HardwareTimer().GetTick() + offset_tick + 2;
93 if (timeout <= 0) {
94 timeout = std::numeric_limits<s64>::max();
95 }
96 } else {
97 timeout = std::numeric_limits<s64>::max();
98 }
99 } else {
100 timeout = timeout_ns;
101 }
102 181
103 // Wait for a message. 182Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle,
104 while (true) { 183 uint64_t message, uint64_t buffer_size,
105 // Wait for an object. 184 Handle session_handle) {
106 s32 index; 185 // Get the process and handle table.
107 Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(), 186 auto& process = GetCurrentProcess(system.Kernel());
108 num_handles, timeout); 187 auto& handle_table = process.GetHandleTable();
109 if (result == ResultTimedOut) {
110 R_RETURN(result);
111 }
112 188
113 // Receive the request. 189 // Reserve a new event from the process resource limit.
114 if (R_SUCCEEDED(result)) { 190 KScopedResourceReservation event_reservation(std::addressof(process),
115 KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); 191 Svc::LimitableResource::EventCountMax);
116 if (session != nullptr) { 192 R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
117 result = session->ReceiveRequest();
118 if (result == ResultNotFound) {
119 continue;
120 }
121 }
122 }
123 193
124 *out_index = index; 194 // Get the client session.
125 R_RETURN(result); 195 KScopedAutoObject session = process.GetHandleTable().GetObject<KClientSession>(session_handle);
126 } 196 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
197
198 // Get the parent, and persist a reference to it until we're done.
199 KScopedAutoObject parent = session->GetParent();
200 ASSERT(parent.IsNotNull());
201
202 // Create a new event.
203 KEvent* event = KEvent::Create(system.Kernel());
204 R_UNLESS(event != nullptr, ResultOutOfResource);
205
206 // Initialize the event.
207 event->Initialize(std::addressof(process));
208
209 // Commit our reservation.
210 event_reservation.Commit();
211
212 // At end of scope, kill the standing references to the sub events.
213 SCOPE_EXIT({
214 event->GetReadableEvent().Close();
215 event->Close();
216 });
217
218 // Register the event.
219 KEvent::Register(system.Kernel(), event);
220
221 // Add the readable event to the handle table.
222 R_TRY(handle_table.Add(out_event_handle, std::addressof(event->GetReadableEvent())));
223
224 // Ensure that if we fail to send the request, we close the readable handle.
225 ON_RESULT_FAILURE {
226 handle_table.Remove(*out_event_handle);
227 };
228
229 // Send the async request.
230 R_RETURN(session->SendAsyncRequest(event, message, buffer_size));
127} 231}
128 232
129Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index, 233Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles, s32 num_handles,
130 uint64_t message_buffer, uint64_t message_buffer_size, 234 Handle reply_target, s64 timeout_ns) {
131 uint64_t handles, int32_t num_handles, Handle reply_target, 235 R_RETURN(ReplyAndReceiveImpl(system.Kernel(), out_index, 0, 0, 0, handles, num_handles,
132 int64_t timeout_ns) { 236 reply_target, timeout_ns));
133 UNIMPLEMENTED(); 237}
134 R_THROW(ResultNotImplemented); 238
239Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index, uint64_t message,
240 uint64_t buffer_size, uint64_t handles, int32_t num_handles,
241 Handle reply_target, int64_t timeout_ns) {
242 // Validate that the message buffer is page aligned and does not overflow.
243 R_UNLESS(Common::IsAligned(message, PageSize), ResultInvalidAddress);
244 R_UNLESS(buffer_size > 0, ResultInvalidSize);
245 R_UNLESS(Common::IsAligned(buffer_size, PageSize), ResultInvalidSize);
246 R_UNLESS(message < message + buffer_size, ResultInvalidCurrentMemory);
247
248 // Get the process page table.
249 auto& page_table = GetCurrentProcess(system.Kernel()).GetPageTable();
250
251 // Lock the message buffer, getting its physical address.
252 KPhysicalAddress message_paddr;
253 R_TRY(page_table.LockForIpcUserBuffer(std::addressof(message_paddr), message, buffer_size));
254
255 {
256 // If we fail to send the message, unlock the message buffer.
257 ON_RESULT_FAILURE {
258 page_table.UnlockForIpcUserBuffer(message, buffer_size);
259 };
260
261 // Reply/Receive the request.
262 ASSERT(message != 0);
263 R_TRY(ReplyAndReceiveImpl(system.Kernel(), out_index, message, buffer_size, message_paddr,
264 handles, num_handles, reply_target, timeout_ns));
265 }
266
267 // We successfully processed, so try to unlock the message buffer.
268 R_RETURN(page_table.UnlockForIpcUserBuffer(message, buffer_size));
135} 269}
136 270
137Result SendSyncRequest64(Core::System& system, Handle session_handle) { 271Result SendSyncRequest64(Core::System& system, Handle session_handle) {
diff --git a/src/core/hle/kernel/svc/svc_light_ipc.cpp b/src/core/hle/kernel/svc/svc_light_ipc.cpp
index b76ce984c..4772cbda1 100644
--- a/src/core/hle/kernel/svc/svc_light_ipc.cpp
+++ b/src/core/hle/kernel/svc/svc_light_ipc.cpp
@@ -1,21 +1,40 @@
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/arm/arm_interface.h"
5#include "core/core.h" 4#include "core/core.h"
5#include "core/hle/kernel/k_light_client_session.h"
6#include "core/hle/kernel/k_light_server_session.h"
7#include "core/hle/kernel/k_process.h"
8#include "core/hle/kernel/k_thread.h"
6#include "core/hle/kernel/svc.h" 9#include "core/hle/kernel/svc.h"
7#include "core/hle/kernel/svc_results.h" 10#include "core/hle/kernel/svc_results.h"
8 11
9namespace Kernel::Svc { 12namespace Kernel::Svc {
10 13
11Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) { 14Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) {
12 UNIMPLEMENTED(); 15 // Get the light client session from its handle.
13 R_THROW(ResultNotImplemented); 16 KScopedAutoObject session = GetCurrentProcess(system.Kernel())
17 .GetHandleTable()
18 .GetObject<KLightClientSession>(session_handle);
19 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
20
21 // Send the request.
22 R_TRY(session->SendSyncRequest(args));
23
24 R_SUCCEED();
14} 25}
15 26
16Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) { 27Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) {
17 UNIMPLEMENTED(); 28 // Get the light server session from its handle.
18 R_THROW(ResultNotImplemented); 29 KScopedAutoObject session = GetCurrentProcess(system.Kernel())
30 .GetHandleTable()
31 .GetObject<KLightServerSession>(session_handle);
32 R_UNLESS(session.IsNotNull(), ResultInvalidHandle);
33
34 // Handle the request.
35 R_TRY(session->ReplyAndReceive(args));
36
37 R_SUCCEED();
19} 38}
20 39
21Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) { 40Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) {
@@ -37,37 +56,36 @@ Result ReplyAndReceiveLight64From32(Core::System& system, Handle session_handle,
37// Custom ABI implementation for light IPC. 56// Custom ABI implementation for light IPC.
38 57
39template <typename F> 58template <typename F>
40static void SvcWrap_LightIpc(Core::System& system, F&& cb) { 59static void SvcWrap_LightIpc(Core::System& system, std::span<uint64_t, 8> args, F&& cb) {
41 auto& core = system.CurrentArmInterface(); 60 std::array<u32, 7> ipc_args{};
42 std::array<u32, 7> arguments{};
43 61
44 Handle session_handle = static_cast<Handle>(core.GetReg(0)); 62 Handle session_handle = static_cast<Handle>(args[0]);
45 for (int i = 0; i < 7; i++) { 63 for (int i = 0; i < 7; i++) {
46 arguments[i] = static_cast<u32>(core.GetReg(i + 1)); 64 ipc_args[i] = static_cast<u32>(args[i + 1]);
47 } 65 }
48 66
49 Result ret = cb(system, session_handle, arguments.data()); 67 Result ret = cb(system, session_handle, ipc_args.data());
50 68
51 core.SetReg(0, ret.raw); 69 args[0] = ret.raw;
52 for (int i = 0; i < 7; i++) { 70 for (int i = 0; i < 7; i++) {
53 core.SetReg(i + 1, arguments[i]); 71 args[i + 1] = ipc_args[i];
54 } 72 }
55} 73}
56 74
57void SvcWrap_SendSyncRequestLight64(Core::System& system) { 75void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args) {
58 SvcWrap_LightIpc(system, SendSyncRequestLight64); 76 SvcWrap_LightIpc(system, args, SendSyncRequestLight64);
59} 77}
60 78
61void SvcWrap_ReplyAndReceiveLight64(Core::System& system) { 79void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args) {
62 SvcWrap_LightIpc(system, ReplyAndReceiveLight64); 80 SvcWrap_LightIpc(system, args, ReplyAndReceiveLight64);
63} 81}
64 82
65void SvcWrap_SendSyncRequestLight64From32(Core::System& system) { 83void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args) {
66 SvcWrap_LightIpc(system, SendSyncRequestLight64From32); 84 SvcWrap_LightIpc(system, args, SendSyncRequestLight64From32);
67} 85}
68 86
69void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system) { 87void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args) {
70 SvcWrap_LightIpc(system, ReplyAndReceiveLight64From32); 88 SvcWrap_LightIpc(system, args, ReplyAndReceiveLight64From32);
71} 89}
72 90
73} // namespace Kernel::Svc 91} // namespace Kernel::Svc
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp
index abba757c7..737749f7d 100644
--- a/src/core/hle/kernel/svc/svc_port.cpp
+++ b/src/core/hle/kernel/svc/svc_port.cpp
@@ -5,6 +5,7 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/kernel/k_client_port.h" 6#include "core/hle/kernel/k_client_port.h"
7#include "core/hle/kernel/k_client_session.h" 7#include "core/hle/kernel/k_client_session.h"
8#include "core/hle/kernel/k_light_client_session.h"
8#include "core/hle/kernel/k_object_name.h" 9#include "core/hle/kernel/k_object_name.h"
9#include "core/hle/kernel/k_port.h" 10#include "core/hle/kernel/k_port.h"
10#include "core/hle/kernel/k_process.h" 11#include "core/hle/kernel/k_process.h"
@@ -51,13 +52,73 @@ Result ConnectToNamedPort(Core::System& system, Handle* out, u64 user_name) {
51 52
52Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, 53Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client,
53 int32_t max_sessions, bool is_light, uint64_t name) { 54 int32_t max_sessions, bool is_light, uint64_t name) {
54 UNIMPLEMENTED(); 55 auto& kernel = system.Kernel();
55 R_THROW(ResultNotImplemented); 56
57 // Ensure max sessions is valid.
58 R_UNLESS(max_sessions > 0, ResultOutOfRange);
59
60 // Get the current handle table.
61 auto& handle_table = GetCurrentProcess(kernel).GetHandleTable();
62
63 // Create a new port.
64 KPort* port = KPort::Create(kernel);
65 R_UNLESS(port != nullptr, ResultOutOfResource);
66
67 // Initialize the port.
68 port->Initialize(max_sessions, is_light, name);
69
70 // Ensure that we clean up the port (and its only references are handle table) on function end.
71 SCOPE_EXIT({
72 port->GetServerPort().Close();
73 port->GetClientPort().Close();
74 });
75
76 // Register the port.
77 KPort::Register(kernel, port);
78
79 // Add the client to the handle table.
80 R_TRY(handle_table.Add(out_client, std::addressof(port->GetClientPort())));
81
82 // Ensure that we maintain a clean handle state on exit.
83 ON_RESULT_FAILURE {
84 handle_table.Remove(*out_client);
85 };
86
87 // Add the server to the handle table.
88 R_RETURN(handle_table.Add(out_server, std::addressof(port->GetServerPort())));
56} 89}
57 90
58Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) { 91Result ConnectToPort(Core::System& system, Handle* out, Handle port) {
59 UNIMPLEMENTED(); 92 // Get the current handle table.
60 R_THROW(ResultNotImplemented); 93 auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
94
95 // Get the client port.
96 KScopedAutoObject client_port = handle_table.GetObject<KClientPort>(port);
97 R_UNLESS(client_port.IsNotNull(), ResultInvalidHandle);
98
99 // Reserve a handle for the port.
100 // NOTE: Nintendo really does write directly to the output handle here.
101 R_TRY(handle_table.Reserve(out));
102 ON_RESULT_FAILURE {
103 handle_table.Unreserve(*out);
104 };
105
106 // Create the session.
107 KAutoObject* session;
108 if (client_port->IsLight()) {
109 R_TRY(client_port->CreateLightSession(
110 reinterpret_cast<KLightClientSession**>(std::addressof(session))));
111 } else {
112 R_TRY(client_port->CreateSession(
113 reinterpret_cast<KClientSession**>(std::addressof(session))));
114 }
115
116 // Register the session.
117 handle_table.Register(*out, session);
118 session->Close();
119
120 // We succeeded.
121 R_SUCCEED();
61} 122}
62 123
63Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name, 124Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name,
diff --git a/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp b/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp
index 62c781551..48b564ec8 100644
--- a/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp
+++ b/src/core/hle/kernel/svc/svc_secure_monitor_call.cpp
@@ -22,31 +22,29 @@ void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArgumen
22 22
23// Custom ABI for CallSecureMonitor. 23// Custom ABI for CallSecureMonitor.
24 24
25void SvcWrap_CallSecureMonitor64(Core::System& system) { 25void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args) {
26 auto& core = system.CurrentPhysicalCore().ArmInterface(); 26 lp64::SecureMonitorArguments smc_args{};
27 lp64::SecureMonitorArguments args{};
28 for (int i = 0; i < 8; i++) { 27 for (int i = 0; i < 8; i++) {
29 args.r[i] = core.GetReg(i); 28 smc_args.r[i] = args[i];
30 } 29 }
31 30
32 CallSecureMonitor64(system, std::addressof(args)); 31 CallSecureMonitor64(system, std::addressof(smc_args));
33 32
34 for (int i = 0; i < 8; i++) { 33 for (int i = 0; i < 8; i++) {
35 core.SetReg(i, args.r[i]); 34 args[i] = smc_args.r[i];
36 } 35 }
37} 36}
38 37
39void SvcWrap_CallSecureMonitor64From32(Core::System& system) { 38void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args) {
40 auto& core = system.CurrentPhysicalCore().ArmInterface(); 39 ilp32::SecureMonitorArguments smc_args{};
41 ilp32::SecureMonitorArguments args{};
42 for (int i = 0; i < 8; i++) { 40 for (int i = 0; i < 8; i++) {
43 args.r[i] = static_cast<u32>(core.GetReg(i)); 41 smc_args.r[i] = static_cast<u32>(args[i]);
44 } 42 }
45 43
46 CallSecureMonitor64From32(system, std::addressof(args)); 44 CallSecureMonitor64From32(system, std::addressof(smc_args));
47 45
48 for (int i = 0; i < 8; i++) { 46 for (int i = 0; i < 8; i++) {
49 core.SetReg(i, args.r[i]); 47 args[i] = smc_args.r[i];
50 } 48 }
51} 49}
52 50
diff --git a/src/core/hle/kernel/svc/svc_session.cpp b/src/core/hle/kernel/svc/svc_session.cpp
index 01b8a52ad..2f5905f32 100644
--- a/src/core/hle/kernel/svc/svc_session.cpp
+++ b/src/core/hle/kernel/svc/svc_session.cpp
@@ -3,8 +3,10 @@
3 3
4#include "common/scope_exit.h" 4#include "common/scope_exit.h"
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/kernel/k_light_session.h"
6#include "core/hle/kernel/k_process.h" 7#include "core/hle/kernel/k_process.h"
7#include "core/hle/kernel/k_scoped_resource_reservation.h" 8#include "core/hle/kernel/k_scoped_resource_reservation.h"
9#include "core/hle/kernel/k_server_port.h"
8#include "core/hle/kernel/k_session.h" 10#include "core/hle/kernel/k_session.h"
9#include "core/hle/kernel/svc.h" 11#include "core/hle/kernel/svc.h"
10 12
@@ -20,7 +22,7 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
20 T* session; 22 T* session;
21 23
22 // Reserve a new session from the process resource limit. 24 // Reserve a new session from the process resource limit.
23 // FIXME: LimitableResource_SessionCountMax 25 // TODO: Dynamic resource limits
24 KScopedResourceReservation session_reservation(std::addressof(process), 26 KScopedResourceReservation session_reservation(std::addressof(process),
25 LimitableResource::SessionCountMax); 27 LimitableResource::SessionCountMax);
26 if (session_reservation.Succeeded()) { 28 if (session_reservation.Succeeded()) {
@@ -92,16 +94,42 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
92Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light, 94Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light,
93 u64 name) { 95 u64 name) {
94 if (is_light) { 96 if (is_light) {
95 // return CreateSession<KLightSession>(system, out_server, out_client, name); 97 R_RETURN(CreateSession<KLightSession>(system, out_server, out_client, name));
96 R_THROW(ResultNotImplemented);
97 } else { 98 } else {
98 R_RETURN(CreateSession<KSession>(system, out_server, out_client, name)); 99 R_RETURN(CreateSession<KSession>(system, out_server, out_client, name));
99 } 100 }
100} 101}
101 102
102Result AcceptSession(Core::System& system, Handle* out_handle, Handle port_handle) { 103Result AcceptSession(Core::System& system, Handle* out, Handle port_handle) {
103 UNIMPLEMENTED(); 104 // Get the current handle table.
104 R_THROW(ResultNotImplemented); 105 auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
106
107 // Get the server port.
108 KScopedAutoObject port = handle_table.GetObject<KServerPort>(port_handle);
109 R_UNLESS(port.IsNotNull(), ResultInvalidHandle);
110
111 // Reserve an entry for the new session.
112 R_TRY(handle_table.Reserve(out));
113 ON_RESULT_FAILURE {
114 handle_table.Unreserve(*out);
115 };
116
117 // Accept the session.
118 KAutoObject* session;
119 if (port->IsLight()) {
120 session = port->AcceptLightSession();
121 } else {
122 session = port->AcceptSession();
123 }
124
125 // Ensure we accepted successfully.
126 R_UNLESS(session != nullptr, ResultNotFound);
127
128 // Register the session.
129 handle_table.Register(*out, session);
130 session->Close();
131
132 R_SUCCEED();
105} 133}
106 134
107Result CreateSession64(Core::System& system, Handle* out_server_session_handle, 135Result CreateSession64(Core::System& system, Handle* out_server_session_handle,
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp
index 755fd62b5..7681afa33 100644
--- a/src/core/hle/kernel/svc/svc_thread.cpp
+++ b/src/core/hle/kernel/svc/svc_thread.cpp
@@ -90,8 +90,6 @@ Result StartThread(Core::System& system, Handle thread_handle) {
90 90
91/// Called when a thread exits 91/// Called when a thread exits
92void ExitThread(Core::System& system) { 92void ExitThread(Core::System& system) {
93 LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC());
94
95 auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); 93 auto* const current_thread = GetCurrentThreadPointer(system.Kernel());
96 system.GlobalSchedulerContext().RemoveThread(current_thread); 94 system.GlobalSchedulerContext().RemoveThread(current_thread);
97 current_thread->Exit(); 95 current_thread->Exit();
@@ -147,47 +145,19 @@ Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_ha
147 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); 145 R_UNLESS(thread.IsNotNull(), ResultInvalidHandle);
148 146
149 // Require the handle be to a non-current thread in the current process. 147 // Require the handle be to a non-current thread in the current process.
150 const auto* current_process = GetCurrentProcessPointer(kernel); 148 R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(kernel), ResultInvalidHandle);
151 R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId); 149 R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultBusy);
152
153 // Verify that the thread isn't terminated.
154 R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested);
155
156 /// Check that the thread is not the current one.
157 /// NOTE: Nintendo does not check this, and thus the following loop will deadlock.
158 R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId);
159
160 // Try to get the thread context until the thread isn't current on any core.
161 while (true) {
162 KScopedSchedulerLock sl{kernel};
163
164 // TODO(bunnei): Enforce that thread is suspended for debug here.
165
166 // If the thread's raw state isn't runnable, check if it's current on some core.
167 if (thread->GetRawState() != ThreadState::Runnable) {
168 bool current = false;
169 for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) {
170 if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetSchedulerCurrentThread()) {
171 current = true;
172 break;
173 }
174 }
175 150
176 // If the thread is current, retry until it isn't. 151 // Get the thread context.
177 if (current) { 152 Svc::ThreadContext context{};
178 continue; 153 R_TRY(thread->GetThreadContext3(std::addressof(context)));
179 }
180 }
181 154
182 // Get the thread context. 155 // Copy the thread context to user space.
183 static thread_local Common::ScratchBuffer<u8> context; 156 R_UNLESS(
184 R_TRY(thread->GetThreadContext3(context)); 157 GetCurrentMemory(kernel).WriteBlock(out_context, std::addressof(context), sizeof(context)),
158 ResultInvalidPointer);
185 159
186 // Copy the thread context to user space. 160 R_SUCCEED();
187 GetCurrentMemory(kernel).WriteBlock(out_context, context.data(), context.size());
188
189 R_SUCCEED();
190 }
191} 161}
192 162
193/// Gets the priority for the specified thread 163/// Gets the priority for the specified thread
diff --git a/src/core/hle/kernel/svc_generator.py b/src/core/hle/kernel/svc_generator.py
index 5531faac6..786189ab7 100644
--- a/src/core/hle/kernel/svc_generator.py
+++ b/src/core/hle/kernel/svc_generator.py
@@ -374,11 +374,11 @@ def get_registers(parse_result, bitness):
374 374
375# Collects possibly multiple source registers into the named C++ value. 375# Collects possibly multiple source registers into the named C++ value.
376def emit_gather(sources, name, type_name, reg_size): 376def emit_gather(sources, name, type_name, reg_size):
377 get_fn = f"GetReg{reg_size*8}" 377 get_fn = f"GetArg{reg_size*8}"
378 378
379 if len(sources) == 1: 379 if len(sources) == 1:
380 s, = sources 380 s, = sources
381 line = f"{name} = Convert<{type_name}>({get_fn}(system, {s}));" 381 line = f"{name} = Convert<{type_name}>({get_fn}(args, {s}));"
382 return [line] 382 return [line]
383 383
384 var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>" 384 var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>"
@@ -387,7 +387,7 @@ def emit_gather(sources, name, type_name, reg_size):
387 ] 387 ]
388 for i in range(0, len(sources)): 388 for i in range(0, len(sources)):
389 lines.append( 389 lines.append(
390 f"{name}_gather[{i}] = {get_fn}(system, {sources[i]});") 390 f"{name}_gather[{i}] = {get_fn}(args, {sources[i]});")
391 391
392 lines.append(f"{name} = Convert<{type_name}>({name}_gather);") 392 lines.append(f"{name} = Convert<{type_name}>({name}_gather);")
393 return lines 393 return lines
@@ -396,12 +396,12 @@ def emit_gather(sources, name, type_name, reg_size):
396# Produces one or more statements which assign the named C++ value 396# Produces one or more statements which assign the named C++ value
397# into possibly multiple registers. 397# into possibly multiple registers.
398def emit_scatter(destinations, name, reg_size): 398def emit_scatter(destinations, name, reg_size):
399 set_fn = f"SetReg{reg_size*8}" 399 set_fn = f"SetArg{reg_size*8}"
400 reg_type = f"uint{reg_size*8}_t" 400 reg_type = f"uint{reg_size*8}_t"
401 401
402 if len(destinations) == 1: 402 if len(destinations) == 1:
403 d, = destinations 403 d, = destinations
404 line = f"{set_fn}(system, {d}, Convert<{reg_type}>({name}));" 404 line = f"{set_fn}(args, {d}, Convert<{reg_type}>({name}));"
405 return [line] 405 return [line]
406 406
407 var_type = f"std::array<{reg_type}, {len(destinations)}>" 407 var_type = f"std::array<{reg_type}, {len(destinations)}>"
@@ -411,7 +411,7 @@ def emit_scatter(destinations, name, reg_size):
411 411
412 for i in range(0, len(destinations)): 412 for i in range(0, len(destinations)):
413 lines.append( 413 lines.append(
414 f"{set_fn}(system, {destinations[i]}, {name}_scatter[{i}]);") 414 f"{set_fn}(args, {destinations[i]}, {name}_scatter[{i}]);")
415 415
416 return lines 416 return lines
417 417
@@ -433,7 +433,7 @@ def emit_lines(lines, indent=' '):
433def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size): 433def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
434 return_write, output_writes, input_reads = register_info 434 return_write, output_writes, input_reads = register_info
435 lines = [ 435 lines = [
436 f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system) {{" 436 f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system, std::span<uint64_t, 8> args) {{"
437 ] 437 ]
438 438
439 # Get everything ready. 439 # Get everything ready.
@@ -498,6 +498,8 @@ namespace Core {
498class System; 498class System;
499} 499}
500 500
501#include <span>
502
501#include "common/common_types.h" 503#include "common/common_types.h"
502#include "core/hle/kernel/svc_types.h" 504#include "core/hle/kernel/svc_types.h"
503#include "core/hle/result.h" 505#include "core/hle/result.h"
@@ -524,15 +526,15 @@ void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArgumen
524void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args); 526void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args);
525 527
526// Defined in svc_light_ipc.cpp. 528// Defined in svc_light_ipc.cpp.
527void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system); 529void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args);
528void SvcWrap_ReplyAndReceiveLight64(Core::System& system); 530void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args);
529 531
530void SvcWrap_SendSyncRequestLight64From32(Core::System& system); 532void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args);
531void SvcWrap_SendSyncRequestLight64(Core::System& system); 533void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args);
532 534
533// Defined in svc_secure_monitor_call.cpp. 535// Defined in svc_secure_monitor_call.cpp.
534void SvcWrap_CallSecureMonitor64From32(Core::System& system); 536void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args);
535void SvcWrap_CallSecureMonitor64(Core::System& system); 537void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args);
536 538
537// Perform a supervisor call by index. 539// Perform a supervisor call by index.
538void Call(Core::System& system, u32 imm); 540void Call(Core::System& system, u32 imm);
@@ -550,20 +552,20 @@ PROLOGUE_CPP = """
550 552
551namespace Kernel::Svc { 553namespace Kernel::Svc {
552 554
553static uint32_t GetReg32(Core::System& system, int n) { 555static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
554 return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n)); 556 return static_cast<uint32_t>(args[n]);
555} 557}
556 558
557static void SetReg32(Core::System& system, int n, uint32_t result) { 559static void SetArg32(std::span<uint64_t, 8> args, int n, uint32_t result) {
558 system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result)); 560 args[n] = result;
559} 561}
560 562
561static uint64_t GetReg64(Core::System& system, int n) { 563static uint64_t GetArg64(std::span<uint64_t, 8> args, int n) {
562 return system.CurrentArmInterface().GetReg(n); 564 return args[n];
563} 565}
564 566
565static void SetReg64(Core::System& system, int n, uint64_t result) { 567static void SetArg64(std::span<uint64_t, 8> args, int n, uint64_t result) {
566 system.CurrentArmInterface().SetReg(n, result); 568 args[n] = result;
567} 569}
568 570
569// Like bit_cast, but handles the case when the source and dest 571// Like bit_cast, but handles the case when the source and dest
@@ -590,15 +592,20 @@ EPILOGUE_CPP = """
590 592
591void Call(Core::System& system, u32 imm) { 593void Call(Core::System& system, u32 imm) {
592 auto& kernel = system.Kernel(); 594 auto& kernel = system.Kernel();
595 auto& process = GetCurrentProcess(kernel);
596
597 std::array<uint64_t, 8> args;
598 kernel.CurrentPhysicalCore().SaveSvcArguments(process, args);
593 kernel.EnterSVCProfile(); 599 kernel.EnterSVCProfile();
594 600
595 if (GetCurrentProcess(system.Kernel()).Is64Bit()) { 601 if (process.Is64Bit()) {
596 Call64(system, imm); 602 Call64(system, imm, args);
597 } else { 603 } else {
598 Call32(system, imm); 604 Call32(system, imm, args);
599 } 605 }
600 606
601 kernel.ExitSVCProfile(); 607 kernel.ExitSVCProfile();
608 kernel.CurrentPhysicalCore().LoadSvcArguments(process, args);
602} 609}
603 610
604} // namespace Kernel::Svc 611} // namespace Kernel::Svc
@@ -609,13 +616,13 @@ def emit_call(bitness, names, suffix):
609 bit_size = REG_SIZES[bitness]*8 616 bit_size = REG_SIZES[bitness]*8
610 indent = " " 617 indent = " "
611 lines = [ 618 lines = [
612 f"static void Call{bit_size}(Core::System& system, u32 imm) {{", 619 f"static void Call{bit_size}(Core::System& system, u32 imm, std::span<uint64_t, 8> args) {{",
613 f"{indent}switch (static_cast<SvcId>(imm)) {{" 620 f"{indent}switch (static_cast<SvcId>(imm)) {{"
614 ] 621 ]
615 622
616 for _, name in names: 623 for _, name in names:
617 lines.append(f"{indent}case SvcId::{name}:") 624 lines.append(f"{indent}case SvcId::{name}:")
618 lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system);") 625 lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system, args);")
619 626
620 lines.append(f"{indent}default:") 627 lines.append(f"{indent}default:")
621 lines.append( 628 lines.append(
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 126cd6ffd..b1310d6e4 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -246,7 +246,13 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
246 entries.reserve(entries.size() + new_data.size()); 246 entries.reserve(entries.size() + new_data.size());
247 247
248 for (const auto& new_entry : new_data) { 248 for (const auto& new_entry : new_data) {
249 entries.emplace_back(new_entry->GetName(), type, 249 auto name = new_entry->GetName();
250
251 if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) {
252 continue;
253 }
254
255 entries.emplace_back(name, type,
250 type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize()); 256 type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize());
251 } 257 }
252} 258}
diff --git a/src/core/hle/service/hid/controllers/applet_resource.cpp b/src/core/hle/service/hid/controllers/applet_resource.cpp
new file mode 100644
index 000000000..c8e74c764
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/applet_resource.cpp
@@ -0,0 +1,313 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/core.h"
5#include "core/hle/kernel/k_shared_memory.h"
6#include "core/hle/service/hid/controllers/applet_resource.h"
7#include "core/hle/service/hid/controllers/shared_memory_format.h"
8#include "core/hle/service/hid/errors.h"
9
10namespace Service::HID {
11
12AppletResource::AppletResource(Core::System& system_) : system{system_} {}
13
14AppletResource::~AppletResource() = default;
15
16Result AppletResource::CreateAppletResource(u64 aruid) {
17 const u64 index = GetIndexFromAruid(aruid);
18
19 if (index >= AruidIndexMax) {
20 return ResultAruidNotRegistered;
21 }
22
23 if (data[index].flag.is_assigned) {
24 return ResultAruidAlreadyRegistered;
25 }
26
27 auto& shared_memory = shared_memory_holder[index];
28 if (!shared_memory.IsMapped()) {
29 const Result result = shared_memory.Initialize(system);
30 if (result.IsError()) {
31 return result;
32 }
33 if (shared_memory.GetAddress() == nullptr) {
34 shared_memory.Finalize();
35 return ResultSharedMemoryNotInitialized;
36 }
37 }
38
39 auto* shared_memory_format = shared_memory.GetAddress();
40 if (shared_memory_format != nullptr) {
41 shared_memory_format->Initialize();
42 }
43
44 data[index].shared_memory_format = shared_memory_format;
45 data[index].flag.is_assigned.Assign(true);
46 // TODO: InitializeSixAxisControllerConfig(false);
47 active_aruid = aruid;
48 return ResultSuccess;
49}
50
51Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input) {
52 const u64 index = GetIndexFromAruid(aruid);
53
54 if (index < AruidIndexMax) {
55 return ResultAruidAlreadyRegistered;
56 }
57
58 std::size_t data_index = AruidIndexMax;
59 for (std::size_t i = 0; i < AruidIndexMax; i++) {
60 if (!data[i].flag.is_initialized) {
61 data_index = i;
62 break;
63 }
64 }
65
66 if (data_index == AruidIndexMax) {
67 return ResultAruidNoAvailableEntries;
68 }
69
70 AruidData& aruid_data = data[data_index];
71
72 aruid_data.aruid = aruid;
73 aruid_data.flag.is_initialized.Assign(true);
74 if (enable_input) {
75 aruid_data.flag.enable_pad_input.Assign(true);
76 aruid_data.flag.enable_six_axis_sensor.Assign(true);
77 aruid_data.flag.bit_18.Assign(true);
78 aruid_data.flag.enable_touchscreen.Assign(true);
79 }
80
81 data_index = AruidIndexMax;
82 for (std::size_t i = 0; i < AruidIndexMax; i++) {
83 if (registration_list.flag[i] == RegistrationStatus::Initialized) {
84 if (registration_list.aruid[i] != aruid) {
85 continue;
86 }
87 data_index = i;
88 break;
89 }
90 if (registration_list.flag[i] == RegistrationStatus::None) {
91 data_index = i;
92 break;
93 }
94 }
95
96 if (data_index == AruidIndexMax) {
97 return ResultSuccess;
98 }
99
100 registration_list.flag[data_index] = RegistrationStatus::Initialized;
101 registration_list.aruid[data_index] = aruid;
102
103 return ResultSuccess;
104}
105
106void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
107 u64 index = GetIndexFromAruid(aruid);
108
109 if (index < AruidIndexMax) {
110 if (data[index].flag.is_assigned) {
111 data[index].shared_memory_format = nullptr;
112 data[index].flag.is_assigned.Assign(false);
113 }
114 }
115
116 index = GetIndexFromAruid(aruid);
117 if (index < AruidIndexMax) {
118 DestroySevenSixAxisTransferMemory();
119 data[index].flag.raw = 0;
120 data[index].aruid = 0;
121
122 index = GetIndexFromAruid(aruid);
123 if (index < AruidIndexMax) {
124 registration_list.flag[index] = RegistrationStatus::PendingDelete;
125 }
126 }
127}
128
129void AppletResource::FreeAppletResourceId(u64 aruid) {
130 u64 index = GetIndexFromAruid(aruid);
131 if (index >= AruidIndexMax) {
132 return;
133 }
134
135 auto& aruid_data = data[index];
136 if (aruid_data.flag.is_assigned) {
137 aruid_data.shared_memory_format = nullptr;
138 aruid_data.flag.is_assigned.Assign(false);
139 }
140}
141
142u64 AppletResource::GetActiveAruid() {
143 return active_aruid;
144}
145
146Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
147 u64 index = GetIndexFromAruid(aruid);
148 if (index >= AruidIndexMax) {
149 return ResultAruidNotRegistered;
150 }
151
152 *out_handle = shared_memory_holder[index].GetHandle();
153 return ResultSuccess;
154}
155
156Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format,
157 u64 aruid) {
158 u64 index = GetIndexFromAruid(aruid);
159 if (index >= AruidIndexMax) {
160 return ResultAruidNotRegistered;
161 }
162
163 *out_shared_memory_format = data[index].shared_memory_format;
164 return ResultSuccess;
165}
166
167u64 AppletResource::GetIndexFromAruid(u64 aruid) {
168 for (std::size_t i = 0; i < AruidIndexMax; i++) {
169 if (registration_list.flag[i] == RegistrationStatus::Initialized &&
170 registration_list.aruid[i] == aruid) {
171 return i;
172 }
173 }
174 return AruidIndexMax;
175}
176
177Result AppletResource::DestroySevenSixAxisTransferMemory() {
178 // TODO
179 return ResultSuccess;
180}
181
182void AppletResource::EnableInput(u64 aruid, bool is_enabled) {
183 const u64 index = GetIndexFromAruid(aruid);
184 if (index >= AruidIndexMax) {
185 return;
186 }
187
188 data[index].flag.enable_pad_input.Assign(is_enabled);
189 data[index].flag.enable_touchscreen.Assign(is_enabled);
190}
191
192void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
193 const u64 index = GetIndexFromAruid(aruid);
194 if (index >= AruidIndexMax) {
195 return;
196 }
197
198 data[index].flag.enable_six_axis_sensor.Assign(is_enabled);
199}
200
201void AppletResource::EnablePadInput(u64 aruid, bool is_enabled) {
202 const u64 index = GetIndexFromAruid(aruid);
203 if (index >= AruidIndexMax) {
204 return;
205 }
206
207 data[index].flag.enable_pad_input.Assign(is_enabled);
208}
209
210void AppletResource::EnableTouchScreen(u64 aruid, bool is_enabled) {
211 const u64 index = GetIndexFromAruid(aruid);
212 if (index >= AruidIndexMax) {
213 return;
214 }
215
216 data[index].flag.enable_touchscreen.Assign(is_enabled);
217}
218
219void AppletResource::SetIsPalmaConnectable(u64 aruid, bool is_connectable) {
220 const u64 index = GetIndexFromAruid(aruid);
221 if (index >= AruidIndexMax) {
222 return;
223 }
224
225 data[index].flag.is_palma_connectable.Assign(is_connectable);
226}
227
228void AppletResource::EnablePalmaBoostMode(u64 aruid, bool is_enabled) {
229 const u64 index = GetIndexFromAruid(aruid);
230 if (index >= AruidIndexMax) {
231 return;
232 }
233
234 data[index].flag.enable_palma_boost_mode.Assign(is_enabled);
235}
236
237Result AppletResource::RegisterCoreAppletResource() {
238 if (ref_counter == std::numeric_limits<s32>::max() - 1) {
239 return ResultAppletResourceOverflow;
240 }
241 if (ref_counter == 0) {
242 const u64 index = GetIndexFromAruid(0);
243 if (index < AruidIndexMax) {
244 return ResultAruidAlreadyRegistered;
245 }
246
247 std::size_t data_index = AruidIndexMax;
248 for (std::size_t i = 0; i < AruidIndexMax; i++) {
249 if (!data[i].flag.is_initialized) {
250 data_index = i;
251 break;
252 }
253 }
254
255 if (data_index == AruidIndexMax) {
256 return ResultAruidNoAvailableEntries;
257 }
258
259 AruidData& aruid_data = data[data_index];
260
261 aruid_data.aruid = 0;
262 aruid_data.flag.is_initialized.Assign(true);
263 aruid_data.flag.enable_pad_input.Assign(true);
264 aruid_data.flag.enable_six_axis_sensor.Assign(true);
265 aruid_data.flag.bit_18.Assign(true);
266 aruid_data.flag.enable_touchscreen.Assign(true);
267
268 data_index = AruidIndexMax;
269 for (std::size_t i = 0; i < AruidIndexMax; i++) {
270 if (registration_list.flag[i] == RegistrationStatus::Initialized) {
271 if (registration_list.aruid[i] != 0) {
272 continue;
273 }
274 data_index = i;
275 break;
276 }
277 if (registration_list.flag[i] == RegistrationStatus::None) {
278 data_index = i;
279 break;
280 }
281 }
282
283 Result result = ResultSuccess;
284
285 if (data_index == AruidIndexMax) {
286 result = CreateAppletResource(0);
287 } else {
288 registration_list.flag[data_index] = RegistrationStatus::Initialized;
289 registration_list.aruid[data_index] = 0;
290 }
291
292 if (result.IsError()) {
293 UnregisterAppletResourceUserId(0);
294 return result;
295 }
296 }
297 ref_counter++;
298 return ResultSuccess;
299}
300
301Result AppletResource::UnregisterCoreAppletResource() {
302 if (ref_counter == 0) {
303 return ResultAppletResourceNotInitialized;
304 }
305
306 if (--ref_counter == 0) {
307 UnregisterAppletResourceUserId(0);
308 }
309
310 return ResultSuccess;
311}
312
313} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/applet_resource.h b/src/core/hle/service/hid/controllers/applet_resource.h
new file mode 100644
index 000000000..e7991f93a
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/applet_resource.h
@@ -0,0 +1,98 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/bit_field.h"
9#include "common/common_types.h"
10#include "core/hle/result.h"
11#include "core/hle/service/hid/controllers/shared_memory_holder.h"
12
13namespace Core {
14class System;
15}
16
17namespace Kernel {
18class KSharedMemory;
19}
20
21namespace Service::HID {
22struct SharedMemoryFormat;
23
24class AppletResource {
25public:
26 explicit AppletResource(Core::System& system_);
27 ~AppletResource();
28
29 Result CreateAppletResource(u64 aruid);
30
31 Result RegisterAppletResourceUserId(u64 aruid, bool enable_input);
32 void UnregisterAppletResourceUserId(u64 aruid);
33
34 void FreeAppletResourceId(u64 aruid);
35
36 u64 GetActiveAruid();
37 Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
38 Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid);
39
40 u64 GetIndexFromAruid(u64 aruid);
41
42 Result DestroySevenSixAxisTransferMemory();
43
44 void EnableInput(u64 aruid, bool is_enabled);
45 void EnableSixAxisSensor(u64 aruid, bool is_enabled);
46 void EnablePadInput(u64 aruid, bool is_enabled);
47 void EnableTouchScreen(u64 aruid, bool is_enabled);
48 void SetIsPalmaConnectable(u64 aruid, bool is_connectable);
49 void EnablePalmaBoostMode(u64 aruid, bool is_enabled);
50
51 Result RegisterCoreAppletResource();
52 Result UnregisterCoreAppletResource();
53
54private:
55 static constexpr std::size_t AruidIndexMax = 0x20;
56
57 enum RegistrationStatus : u32 {
58 None,
59 Initialized,
60 PendingDelete,
61 };
62
63 struct DataStatusFlag {
64 union {
65 u32 raw{};
66
67 BitField<0, 1, u32> is_initialized;
68 BitField<1, 1, u32> is_assigned;
69 BitField<16, 1, u32> enable_pad_input;
70 BitField<17, 1, u32> enable_six_axis_sensor;
71 BitField<18, 1, u32> bit_18;
72 BitField<19, 1, u32> is_palma_connectable;
73 BitField<20, 1, u32> enable_palma_boost_mode;
74 BitField<21, 1, u32> enable_touchscreen;
75 };
76 };
77
78 struct AruidRegisterList {
79 std::array<RegistrationStatus, AruidIndexMax> flag{};
80 std::array<u64, AruidIndexMax> aruid{};
81 };
82 static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size");
83
84 struct AruidData {
85 DataStatusFlag flag{};
86 u64 aruid{};
87 SharedMemoryFormat* shared_memory_format{nullptr};
88 };
89
90 u64 active_aruid{};
91 AruidRegisterList registration_list{};
92 std::array<AruidData, AruidIndexMax> data{};
93 std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{};
94 s32 ref_counter{};
95
96 Core::System& system;
97};
98} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.cpp b/src/core/hle/service/hid/controllers/console_six_axis.cpp
index b2bf1d78d..3961d2b5f 100644
--- a/src/core/hle/service/hid/controllers/console_six_axis.cpp
+++ b/src/core/hle/service/hid/controllers/console_six_axis.cpp
@@ -1,23 +1,18 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 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/core.h"
5#include "core/core_timing.h" 4#include "core/core_timing.h"
6#include "core/hid/emulated_console.h" 5#include "core/hid/emulated_console.h"
7#include "core/hid/hid_core.h" 6#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/console_six_axis.h" 7#include "core/hle/service/hid/controllers/console_six_axis.h"
9#include "core/memory.h" 8#include "core/hle/service/hid/controllers/shared_memory_format.h"
10 9
11namespace Service::HID { 10namespace Service::HID {
12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
13 11
14ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 12ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
15 : ControllerBase{hid_core_} { 13 ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory)
14 : ControllerBase{hid_core_}, shared_memory{console_shared_memory} {
16 console = hid_core.GetEmulatedConsole(); 15 console = hid_core.GetEmulatedConsole();
17 static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
18 "ConsoleSharedMemory is bigger than the shared memory");
19 shared_memory = std::construct_at(
20 reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
21} 16}
22 17
23ConsoleSixAxis::~ConsoleSixAxis() = default; 18ConsoleSixAxis::~ConsoleSixAxis() = default;
@@ -33,10 +28,10 @@ void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
33 28
34 const auto motion_status = console->GetMotion(); 29 const auto motion_status = console->GetMotion();
35 30
36 shared_memory->sampling_number++; 31 shared_memory.sampling_number++;
37 shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; 32 shared_memory.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
38 shared_memory->verticalization_error = motion_status.verticalization_error; 33 shared_memory.verticalization_error = motion_status.verticalization_error;
39 shared_memory->gyro_bias = motion_status.gyro_bias; 34 shared_memory.gyro_bias = motion_status.gyro_bias;
40} 35}
41 36
42} // namespace Service::HID 37} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.h b/src/core/hle/service/hid/controllers/console_six_axis.h
index 5b7c6a29a..3d1c9ce23 100644
--- a/src/core/hle/service/hid/controllers/console_six_axis.h
+++ b/src/core/hle/service/hid/controllers/console_six_axis.h
@@ -3,7 +3,6 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/vector_math.h"
7#include "core/hle/service/hid/controllers/controller_base.h" 6#include "core/hle/service/hid/controllers/controller_base.h"
8 7
9namespace Core::HID { 8namespace Core::HID {
@@ -11,9 +10,12 @@ class EmulatedConsole;
11} // namespace Core::HID 10} // namespace Core::HID
12 11
13namespace Service::HID { 12namespace Service::HID {
13struct ConsoleSixAxisSensorSharedMemoryFormat;
14
14class ConsoleSixAxis final : public ControllerBase { 15class ConsoleSixAxis final : public ControllerBase {
15public: 16public:
16 explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 17 explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
18 ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory);
17 ~ConsoleSixAxis() override; 19 ~ConsoleSixAxis() override;
18 20
19 // Called when the controller is initialized 21 // Called when the controller is initialized
@@ -26,18 +28,7 @@ public:
26 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 28 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
27 29
28private: 30private:
29 // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat 31 ConsoleSixAxisSensorSharedMemoryFormat& shared_memory;
30 struct ConsoleSharedMemory {
31 u64 sampling_number{};
32 bool is_seven_six_axis_sensor_at_rest{};
33 INSERT_PADDING_BYTES(3); // padding
34 f32 verticalization_error{};
35 Common::Vec3f gyro_bias{};
36 INSERT_PADDING_BYTES(4); // padding
37 };
38 static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
39
40 ConsoleSharedMemory* shared_memory = nullptr;
41 Core::HID::EmulatedConsole* console = nullptr; 32 Core::HID::EmulatedConsole* console = nullptr;
42}; 33};
43} // namespace Service::HID 34} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index 9a44ee41e..4326c7821 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -39,9 +39,6 @@ public:
39 39
40 bool IsControllerActivated() const; 40 bool IsControllerActivated() const;
41 41
42 static const std::size_t hid_entry_count = 17;
43 static const std::size_t shared_memory_size = 0x40000;
44
45protected: 42protected:
46 bool is_activated{false}; 43 bool is_activated{false};
47 44
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index 9de19ebfc..7d2370b4f 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -1,24 +1,19 @@
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 <cstring>
5#include "common/common_types.h"
6#include "common/settings.h" 4#include "common/settings.h"
7#include "core/core_timing.h" 5#include "core/core_timing.h"
8#include "core/hid/emulated_controller.h" 6#include "core/hid/emulated_controller.h"
9#include "core/hid/hid_core.h" 7#include "core/hid/hid_core.h"
10#include "core/hid/hid_types.h" 8#include "core/hid/hid_types.h"
11#include "core/hle/service/hid/controllers/debug_pad.h" 9#include "core/hle/service/hid/controllers/debug_pad.h"
10#include "core/hle/service/hid/controllers/shared_memory_format.h"
12 11
13namespace Service::HID { 12namespace Service::HID {
14constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; 13
15 14DebugPad::DebugPad(Core::HID::HIDCore& hid_core_,
16DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 15 DebugPadSharedMemoryFormat& debug_pad_shared_memory)
17 : ControllerBase{hid_core_} { 16 : ControllerBase{hid_core_}, shared_memory{debug_pad_shared_memory} {
18 static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
19 "DebugPadSharedMemory is bigger than the shared memory");
20 shared_memory = std::construct_at(
21 reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
22 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); 17 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
23} 18}
24 19
@@ -30,12 +25,12 @@ void DebugPad::OnRelease() {}
30 25
31void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 26void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
32 if (!IsControllerActivated()) { 27 if (!IsControllerActivated()) {
33 shared_memory->debug_pad_lifo.buffer_count = 0; 28 shared_memory.debug_pad_lifo.buffer_count = 0;
34 shared_memory->debug_pad_lifo.buffer_tail = 0; 29 shared_memory.debug_pad_lifo.buffer_tail = 0;
35 return; 30 return;
36 } 31 }
37 32
38 const auto& last_entry = shared_memory->debug_pad_lifo.ReadCurrentEntry().state; 33 const auto& last_entry = shared_memory.debug_pad_lifo.ReadCurrentEntry().state;
39 next_state.sampling_number = last_entry.sampling_number + 1; 34 next_state.sampling_number = last_entry.sampling_number + 1;
40 35
41 if (Settings::values.debug_pad_enabled) { 36 if (Settings::values.debug_pad_enabled) {
@@ -49,7 +44,7 @@ void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
49 next_state.r_stick = stick_state.right; 44 next_state.r_stick = stick_state.right;
50 } 45 }
51 46
52 shared_memory->debug_pad_lifo.WriteNextEntry(next_state); 47 shared_memory.debug_pad_lifo.WriteNextEntry(next_state);
53} 48}
54 49
55} // namespace Service::HID 50} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 5566dba77..8ab29eca8 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -3,21 +3,24 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8#include "core/hle/service/hid/controllers/controller_base.h" 6#include "core/hle/service/hid/controllers/controller_base.h"
9#include "core/hle/service/hid/ring_lifo.h" 7#include "core/hle/service/hid/controllers/types/debug_pad_types.h"
10 8
11namespace Core::HID { 9namespace Core::HID {
12class EmulatedController; 10class HIDCore;
13struct DebugPadButton; 11}
14struct AnalogStickState; 12
15} // namespace Core::HID 13namespace Core::Timing {
14class CoreTiming;
15}
16 16
17namespace Service::HID { 17namespace Service::HID {
18struct DebugPadSharedMemoryFormat;
19
18class DebugPad final : public ControllerBase { 20class DebugPad final : public ControllerBase {
19public: 21public:
20 explicit DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 22 explicit DebugPad(Core::HID::HIDCore& hid_core_,
23 DebugPadSharedMemoryFormat& debug_pad_shared_memory);
21 ~DebugPad() override; 24 ~DebugPad() override;
22 25
23 // Called when the controller is initialized 26 // Called when the controller is initialized
@@ -30,35 +33,8 @@ public:
30 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 33 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
31 34
32private: 35private:
33 // This is nn::hid::DebugPadAttribute
34 struct DebugPadAttribute {
35 union {
36 u32 raw{};
37 BitField<0, 1, u32> connected;
38 };
39 };
40 static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
41
42 // This is nn::hid::DebugPadState
43 struct DebugPadState {
44 s64 sampling_number{};
45 DebugPadAttribute attribute{};
46 Core::HID::DebugPadButton pad_state{};
47 Core::HID::AnalogStickState r_stick{};
48 Core::HID::AnalogStickState l_stick{};
49 };
50 static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
51
52 struct DebugPadSharedMemory {
53 // This is nn::hid::detail::DebugPadLifo
54 Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{};
55 static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
56 INSERT_PADDING_WORDS(0x4E);
57 };
58 static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size");
59
60 DebugPadState next_state{}; 36 DebugPadState next_state{};
61 DebugPadSharedMemory* shared_memory = nullptr; 37 DebugPadSharedMemoryFormat& shared_memory;
62 Core::HID::EmulatedController* controller = nullptr; 38 Core::HID::EmulatedController* controller = nullptr;
63}; 39};
64} // namespace Service::HID 40} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 59b2ec73c..f658005f6 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -1,17 +1,15 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 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 "common/math_util.h" 4#include "common/math_util.h"
6#include "common/settings.h" 5#include "common/settings.h"
7#include "core/core_timing.h"
8#include "core/frontend/emu_window.h" 6#include "core/frontend/emu_window.h"
7#include "core/hid/emulated_console.h"
9#include "core/hid/hid_core.h" 8#include "core/hid/hid_core.h"
10#include "core/hle/service/hid/controllers/gesture.h" 9#include "core/hle/service/hid/controllers/gesture.h"
10#include "core/hle/service/hid/controllers/shared_memory_format.h"
11 11
12namespace Service::HID { 12namespace Service::HID {
13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
14
15// HW is around 700, value is set to 400 to make it easier to trigger with mouse 13// HW is around 700, value is set to 400 to make it easier to trigger with mouse
16constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s 14constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
17constexpr f32 angle_threshold = 0.015f; // Threshold in radians 15constexpr f32 angle_threshold = 0.015f; // Threshold in radians
@@ -23,19 +21,15 @@ constexpr f32 Square(s32 num) {
23 return static_cast<f32>(num * num); 21 return static_cast<f32>(num * num);
24} 22}
25 23
26Gesture::Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 24Gesture::Gesture(Core::HID::HIDCore& hid_core_, GestureSharedMemoryFormat& gesture_shared_memory)
27 : ControllerBase(hid_core_) { 25 : ControllerBase(hid_core_), shared_memory{gesture_shared_memory} {
28 static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size,
29 "GestureSharedMemory is bigger than the shared memory");
30 shared_memory = std::construct_at(
31 reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
32 console = hid_core.GetEmulatedConsole(); 26 console = hid_core.GetEmulatedConsole();
33} 27}
34Gesture::~Gesture() = default; 28Gesture::~Gesture() = default;
35 29
36void Gesture::OnInit() { 30void Gesture::OnInit() {
37 shared_memory->gesture_lifo.buffer_count = 0; 31 shared_memory.gesture_lifo.buffer_count = 0;
38 shared_memory->gesture_lifo.buffer_tail = 0; 32 shared_memory.gesture_lifo.buffer_tail = 0;
39 force_update = true; 33 force_update = true;
40} 34}
41 35
@@ -43,8 +37,8 @@ void Gesture::OnRelease() {}
43 37
44void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 38void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
45 if (!IsControllerActivated()) { 39 if (!IsControllerActivated()) {
46 shared_memory->gesture_lifo.buffer_count = 0; 40 shared_memory.gesture_lifo.buffer_count = 0;
47 shared_memory->gesture_lifo.buffer_tail = 0; 41 shared_memory.gesture_lifo.buffer_tail = 0;
48 return; 42 return;
49 } 43 }
50 44
@@ -52,7 +46,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
52 46
53 GestureProperties gesture = GetGestureProperties(); 47 GestureProperties gesture = GetGestureProperties();
54 f32 time_difference = 48 f32 time_difference =
55 static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) / 49 static_cast<f32>(shared_memory.gesture_lifo.timestamp - last_update_timestamp) /
56 (1000 * 1000 * 1000); 50 (1000 * 1000 * 1000);
57 51
58 // Only update if necessary 52 // Only update if necessary
@@ -60,7 +54,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
60 return; 54 return;
61 } 55 }
62 56
63 last_update_timestamp = shared_memory->gesture_lifo.timestamp; 57 last_update_timestamp = shared_memory.gesture_lifo.timestamp;
64 UpdateGestureSharedMemory(gesture, time_difference); 58 UpdateGestureSharedMemory(gesture, time_difference);
65} 59}
66 60
@@ -103,7 +97,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
103 GestureType type = GestureType::Idle; 97 GestureType type = GestureType::Idle;
104 GestureAttribute attributes{}; 98 GestureAttribute attributes{};
105 99
106 const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state; 100 const auto& last_entry = shared_memory.gesture_lifo.ReadCurrentEntry().state;
107 101
108 // Reset next state to default 102 // Reset next state to default
109 next_state.sampling_number = last_entry.sampling_number + 1; 103 next_state.sampling_number = last_entry.sampling_number + 1;
@@ -133,7 +127,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
133 next_state.points = gesture.points; 127 next_state.points = gesture.points;
134 last_gesture = gesture; 128 last_gesture = gesture;
135 129
136 shared_memory->gesture_lifo.WriteNextEntry(next_state); 130 shared_memory.gesture_lifo.WriteNextEntry(next_state);
137} 131}
138 132
139void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, 133void Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
@@ -305,11 +299,11 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_
305 next_state.direction = GestureDirection::Up; 299 next_state.direction = GestureDirection::Up;
306} 300}
307 301
308const Gesture::GestureState& Gesture::GetLastGestureEntry() const { 302const GestureState& Gesture::GetLastGestureEntry() const {
309 return shared_memory->gesture_lifo.ReadCurrentEntry().state; 303 return shared_memory.gesture_lifo.ReadCurrentEntry().state;
310} 304}
311 305
312Gesture::GestureProperties Gesture::GetGestureProperties() { 306GestureProperties Gesture::GetGestureProperties() {
313 GestureProperties gesture; 307 GestureProperties gesture;
314 std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; 308 std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
315 const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), 309 const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 4c6f8ee07..41fdfcd03 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -4,17 +4,22 @@
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <array>
7#include "common/bit_field.h" 7
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/point.h"
10#include "core/hid/emulated_console.h"
11#include "core/hle/service/hid/controllers/controller_base.h" 9#include "core/hle/service/hid/controllers/controller_base.h"
12#include "core/hle/service/hid/ring_lifo.h" 10#include "core/hle/service/hid/controllers/types/touch_types.h"
11
12namespace Core::HID {
13class EmulatedConsole;
14}
13 15
14namespace Service::HID { 16namespace Service::HID {
17struct GestureSharedMemoryFormat;
18
15class Gesture final : public ControllerBase { 19class Gesture final : public ControllerBase {
16public: 20public:
17 explicit Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 21 explicit Gesture(Core::HID::HIDCore& hid_core_,
22 GestureSharedMemoryFormat& gesture_shared_memory);
18 ~Gesture() override; 23 ~Gesture() override;
19 24
20 // Called when the controller is initialized 25 // Called when the controller is initialized
@@ -27,79 +32,6 @@ public:
27 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 32 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
28 33
29private: 34private:
30 static constexpr size_t MAX_FINGERS = 16;
31 static constexpr size_t MAX_POINTS = 4;
32
33 // This is nn::hid::GestureType
34 enum class GestureType : u32 {
35 Idle, // Nothing touching the screen
36 Complete, // Set at the end of a touch event
37 Cancel, // Set when the number of fingers change
38 Touch, // A finger just touched the screen
39 Press, // Set if last type is touch and the finger hasn't moved
40 Tap, // Fast press then release
41 Pan, // All points moving together across the screen
42 Swipe, // Fast press movement and release of a single point
43 Pinch, // All points moving away/closer to the midpoint
44 Rotate, // All points rotating from the midpoint
45 };
46
47 // This is nn::hid::GestureDirection
48 enum class GestureDirection : u32 {
49 None,
50 Left,
51 Up,
52 Right,
53 Down,
54 };
55
56 // This is nn::hid::GestureAttribute
57 struct GestureAttribute {
58 union {
59 u32 raw{};
60
61 BitField<4, 1, u32> is_new_touch;
62 BitField<8, 1, u32> is_double_tap;
63 };
64 };
65 static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
66
67 // This is nn::hid::GestureState
68 struct GestureState {
69 s64 sampling_number{};
70 s64 detection_count{};
71 GestureType type{GestureType::Idle};
72 GestureDirection direction{GestureDirection::None};
73 Common::Point<s32> pos{};
74 Common::Point<s32> delta{};
75 f32 vel_x{};
76 f32 vel_y{};
77 GestureAttribute attributes{};
78 f32 scale{};
79 f32 rotation_angle{};
80 s32 point_count{};
81 std::array<Common::Point<s32>, 4> points{};
82 };
83 static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
84
85 struct GestureProperties {
86 std::array<Common::Point<s32>, MAX_POINTS> points{};
87 std::size_t active_points{};
88 Common::Point<s32> mid_point{};
89 s64 detection_count{};
90 u64 delta_time{};
91 f32 average_distance{};
92 f32 angle{};
93 };
94
95 struct GestureSharedMemory {
96 // This is nn::hid::detail::GestureLifo
97 Lifo<GestureState, hid_entry_count> gesture_lifo{};
98 static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
99 INSERT_PADDING_WORDS(0x3E);
100 };
101 static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size");
102
103 // Reads input from all available input engines 35 // Reads input from all available input engines
104 void ReadTouchInput(); 36 void ReadTouchInput();
105 37
@@ -142,7 +74,7 @@ private:
142 GestureProperties GetGestureProperties(); 74 GestureProperties GetGestureProperties();
143 75
144 GestureState next_state{}; 76 GestureState next_state{};
145 GestureSharedMemory* shared_memory = nullptr; 77 GestureSharedMemoryFormat& shared_memory;
146 Core::HID::EmulatedConsole* console = nullptr; 78 Core::HID::EmulatedConsole* console = nullptr;
147 79
148 std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; 80 std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index ddb1b0ba4..871e5036a 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -1,23 +1,18 @@
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 <cstring>
5#include "common/common_types.h"
6#include "common/settings.h" 4#include "common/settings.h"
7#include "core/core_timing.h" 5#include "core/core_timing.h"
8#include "core/hid/emulated_devices.h" 6#include "core/hid/emulated_devices.h"
9#include "core/hid/hid_core.h" 7#include "core/hid/hid_core.h"
10#include "core/hle/service/hid/controllers/keyboard.h" 8#include "core/hle/service/hid/controllers/keyboard.h"
9#include "core/hle/service/hid/controllers/shared_memory_format.h"
11 10
12namespace Service::HID { 11namespace Service::HID {
13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 12
14 13Keyboard::Keyboard(Core::HID::HIDCore& hid_core_,
15Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 14 KeyboardSharedMemoryFormat& keyboard_shared_memory)
16 : ControllerBase{hid_core_} { 15 : ControllerBase{hid_core_}, shared_memory{keyboard_shared_memory} {
17 static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
18 "KeyboardSharedMemory is bigger than the shared memory");
19 shared_memory = std::construct_at(
20 reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
21 emulated_devices = hid_core.GetEmulatedDevices(); 16 emulated_devices = hid_core.GetEmulatedDevices();
22} 17}
23 18
@@ -29,12 +24,12 @@ void Keyboard::OnRelease() {}
29 24
30void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 25void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
31 if (!IsControllerActivated()) { 26 if (!IsControllerActivated()) {
32 shared_memory->keyboard_lifo.buffer_count = 0; 27 shared_memory.keyboard_lifo.buffer_count = 0;
33 shared_memory->keyboard_lifo.buffer_tail = 0; 28 shared_memory.keyboard_lifo.buffer_tail = 0;
34 return; 29 return;
35 } 30 }
36 31
37 const auto& last_entry = shared_memory->keyboard_lifo.ReadCurrentEntry().state; 32 const auto& last_entry = shared_memory.keyboard_lifo.ReadCurrentEntry().state;
38 next_state.sampling_number = last_entry.sampling_number + 1; 33 next_state.sampling_number = last_entry.sampling_number + 1;
39 34
40 if (Settings::values.keyboard_enabled) { 35 if (Settings::values.keyboard_enabled) {
@@ -46,7 +41,7 @@ void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
46 next_state.attribute.is_connected.Assign(1); 41 next_state.attribute.is_connected.Assign(1);
47 } 42 }
48 43
49 shared_memory->keyboard_lifo.WriteNextEntry(next_state); 44 shared_memory.keyboard_lifo.WriteNextEntry(next_state);
50} 45}
51 46
52} // namespace Service::HID 47} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 172ec1309..4d72171b9 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -3,20 +3,16 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_types.h"
7#include "core/hle/service/hid/controllers/controller_base.h" 6#include "core/hle/service/hid/controllers/controller_base.h"
8#include "core/hle/service/hid/ring_lifo.h" 7#include "core/hle/service/hid/controllers/types/keyboard_types.h"
9
10namespace Core::HID {
11class EmulatedDevices;
12struct KeyboardModifier;
13struct KeyboardKey;
14} // namespace Core::HID
15 8
16namespace Service::HID { 9namespace Service::HID {
10struct KeyboardSharedMemoryFormat;
11
17class Keyboard final : public ControllerBase { 12class Keyboard final : public ControllerBase {
18public: 13public:
19 explicit Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 14 explicit Keyboard(Core::HID::HIDCore& hid_core_,
15 KeyboardSharedMemoryFormat& keyboard_shared_memory);
20 ~Keyboard() override; 16 ~Keyboard() override;
21 17
22 // Called when the controller is initialized 18 // Called when the controller is initialized
@@ -29,25 +25,8 @@ public:
29 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 25 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
30 26
31private: 27private:
32 // This is nn::hid::detail::KeyboardState
33 struct KeyboardState {
34 s64 sampling_number{};
35 Core::HID::KeyboardModifier modifier{};
36 Core::HID::KeyboardAttribute attribute{};
37 Core::HID::KeyboardKey key{};
38 };
39 static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
40
41 struct KeyboardSharedMemory {
42 // This is nn::hid::detail::KeyboardLifo
43 Lifo<KeyboardState, hid_entry_count> keyboard_lifo{};
44 static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
45 INSERT_PADDING_WORDS(0xA);
46 };
47 static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size");
48
49 KeyboardState next_state{}; 28 KeyboardState next_state{};
50 KeyboardSharedMemory* shared_memory = nullptr; 29 KeyboardSharedMemoryFormat& shared_memory;
51 Core::HID::EmulatedDevices* emulated_devices = nullptr; 30 Core::HID::EmulatedDevices* emulated_devices = nullptr;
52}; 31};
53} // namespace Service::HID 32} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 6e5a04e34..de5b2c804 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -1,22 +1,17 @@
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 <cstring>
5#include "common/common_types.h"
6#include "core/core_timing.h" 4#include "core/core_timing.h"
7#include "core/frontend/emu_window.h" 5#include "core/frontend/emu_window.h"
8#include "core/hid/emulated_devices.h" 6#include "core/hid/emulated_devices.h"
9#include "core/hid/hid_core.h" 7#include "core/hid/hid_core.h"
10#include "core/hle/service/hid/controllers/mouse.h" 8#include "core/hle/service/hid/controllers/mouse.h"
9#include "core/hle/service/hid/controllers/shared_memory_format.h"
11 10
12namespace Service::HID { 11namespace Service::HID {
13constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
14 12
15Mouse::Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} { 13Mouse::Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory)
16 static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size, 14 : ControllerBase{hid_core_}, shared_memory{mouse_shared_memory} {
17 "MouseSharedMemory is bigger than the shared memory");
18 shared_memory = std::construct_at(
19 reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
20 emulated_devices = hid_core.GetEmulatedDevices(); 15 emulated_devices = hid_core.GetEmulatedDevices();
21} 16}
22 17
@@ -27,14 +22,14 @@ void Mouse::OnRelease() {}
27 22
28void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 23void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
29 if (!IsControllerActivated()) { 24 if (!IsControllerActivated()) {
30 shared_memory->mouse_lifo.buffer_count = 0; 25 shared_memory.mouse_lifo.buffer_count = 0;
31 shared_memory->mouse_lifo.buffer_tail = 0; 26 shared_memory.mouse_lifo.buffer_tail = 0;
32 return; 27 return;
33 } 28 }
34 29
35 next_state = {}; 30 next_state = {};
36 31
37 const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state; 32 const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state;
38 next_state.sampling_number = last_entry.sampling_number + 1; 33 next_state.sampling_number = last_entry.sampling_number + 1;
39 34
40 if (Settings::values.mouse_enabled) { 35 if (Settings::values.mouse_enabled) {
@@ -53,7 +48,7 @@ void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
53 next_state.button = mouse_button_state; 48 next_state.button = mouse_button_state;
54 } 49 }
55 50
56 shared_memory->mouse_lifo.WriteNextEntry(next_state); 51 shared_memory.mouse_lifo.WriteNextEntry(next_state);
57} 52}
58 53
59} // namespace Service::HID 54} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index a80f3823f..363f316a5 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -3,9 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_types.h"
7#include "core/hle/service/hid/controllers/controller_base.h" 6#include "core/hle/service/hid/controllers/controller_base.h"
8#include "core/hle/service/hid/ring_lifo.h"
9 7
10namespace Core::HID { 8namespace Core::HID {
11class EmulatedDevices; 9class EmulatedDevices;
@@ -14,9 +12,11 @@ struct AnalogStickState;
14} // namespace Core::HID 12} // namespace Core::HID
15 13
16namespace Service::HID { 14namespace Service::HID {
15struct MouseSharedMemoryFormat;
16
17class Mouse final : public ControllerBase { 17class Mouse final : public ControllerBase {
18public: 18public:
19 explicit Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 19 explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory);
20 ~Mouse() override; 20 ~Mouse() override;
21 21
22 // Called when the controller is initialized 22 // Called when the controller is initialized
@@ -29,17 +29,9 @@ public:
29 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 29 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
30 30
31private: 31private:
32 struct MouseSharedMemory {
33 // This is nn::hid::detail::MouseLifo
34 Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{};
35 static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
36 INSERT_PADDING_WORDS(0x2C);
37 };
38 static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size");
39
40 Core::HID::MouseState next_state{}; 32 Core::HID::MouseState next_state{};
41 Core::HID::AnalogStickState last_mouse_wheel_state{}; 33 Core::HID::AnalogStickState last_mouse_wheel_state{};
42 MouseSharedMemory* shared_memory = nullptr; 34 MouseSharedMemoryFormat& shared_memory;
43 Core::HID::EmulatedDevices* emulated_devices = nullptr; 35 Core::HID::EmulatedDevices* emulated_devices = nullptr;
44}; 36};
45} // namespace Service::HID 37} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 08ee9de9c..53a737cf5 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -17,12 +17,12 @@
17#include "core/hle/kernel/k_event.h" 17#include "core/hle/kernel/k_event.h"
18#include "core/hle/kernel/k_readable_event.h" 18#include "core/hle/kernel/k_readable_event.h"
19#include "core/hle/service/hid/controllers/npad.h" 19#include "core/hle/service/hid/controllers/npad.h"
20#include "core/hle/service/hid/controllers/shared_memory_format.h"
20#include "core/hle/service/hid/errors.h" 21#include "core/hle/service/hid/errors.h"
21#include "core/hle/service/hid/hid_util.h" 22#include "core/hle/service/hid/hid_util.h"
22#include "core/hle/service/kernel_helpers.h" 23#include "core/hle/service/kernel_helpers.h"
23 24
24namespace Service::HID { 25namespace Service::HID {
25constexpr std::size_t NPAD_OFFSET = 0x9A00;
26constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ 26constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
27 Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, 27 Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3,
28 Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6, 28 Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6,
@@ -30,14 +30,12 @@ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
30 Core::HID::NpadIdType::Handheld, 30 Core::HID::NpadIdType::Handheld,
31}; 31};
32 32
33NPad::NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, 33NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
34 KernelHelpers::ServiceContext& service_context_) 34 KernelHelpers::ServiceContext& service_context_)
35 : ControllerBase{hid_core_}, service_context{service_context_} { 35 : ControllerBase{hid_core_}, service_context{service_context_} {
36 static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size);
37 for (std::size_t i = 0; i < controller_data.size(); ++i) { 36 for (std::size_t i = 0; i < controller_data.size(); ++i) {
38 auto& controller = controller_data[i]; 37 auto& controller = controller_data[i];
39 controller.shared_memory = std::construct_at(reinterpret_cast<NpadInternalState*>( 38 controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state;
40 raw_shared_memory_ + NPAD_OFFSET + (i * sizeof(NpadInternalState))));
41 controller.device = hid_core.GetEmulatedControllerByIndex(i); 39 controller.device = hid_core.GetEmulatedControllerByIndex(i);
42 controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = 40 controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
43 Core::HID::DEFAULT_VIBRATION_VALUE; 41 Core::HID::DEFAULT_VIBRATION_VALUE;
@@ -617,7 +615,7 @@ void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
617 hold_type = joy_hold_type; 615 hold_type = joy_hold_type;
618} 616}
619 617
620NPad::NpadJoyHoldType NPad::GetHoldType() const { 618NpadJoyHoldType NPad::GetHoldType() const {
621 return hold_type; 619 return hold_type;
622} 620}
623 621
@@ -630,7 +628,7 @@ void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_m
630 handheld_activation_mode = activation_mode; 628 handheld_activation_mode = activation_mode;
631} 629}
632 630
633NPad::NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const { 631NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
634 return handheld_activation_mode; 632 return handheld_activation_mode;
635} 633}
636 634
@@ -638,7 +636,7 @@ void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
638 communication_mode = communication_mode_; 636 communication_mode = communication_mode_;
639} 637}
640 638
641NPad::NpadCommunicationMode NPad::GetNpadCommunicationMode() const { 639NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
642 return communication_mode; 640 return communication_mode;
643} 641}
644 642
@@ -978,27 +976,27 @@ Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
978 return ResultSuccess; 976 return ResultSuccess;
979} 977}
980 978
981NPad::SixAxisLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) { 979NpadSixAxisSensorLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
982 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo; 980 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo;
983} 981}
984 982
985NPad::SixAxisLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) { 983NpadSixAxisSensorLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
986 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo; 984 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo;
987} 985}
988 986
989NPad::SixAxisLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) { 987NpadSixAxisSensorLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
990 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo; 988 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo;
991} 989}
992 990
993NPad::SixAxisLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) { 991NpadSixAxisSensorLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
994 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo; 992 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo;
995} 993}
996 994
997NPad::SixAxisLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) { 995NpadSixAxisSensorLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
998 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo; 996 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo;
999} 997}
1000 998
1001NPad::SixAxisLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) { 999NpadSixAxisSensorLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
1002 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo; 1000 return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo;
1003} 1001}
1004 1002
@@ -1343,7 +1341,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
1343 } 1341 }
1344} 1342}
1345 1343
1346NPad::AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) { 1344AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
1347 const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory; 1345 const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory;
1348 1346
1349 return { 1347 return {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 9167c93f0..4e2412356 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -8,12 +8,10 @@
8#include <mutex> 8#include <mutex>
9#include <span> 9#include <span>
10 10
11#include "common/bit_field.h"
12#include "common/common_types.h" 11#include "common/common_types.h"
13
14#include "core/hid/hid_types.h" 12#include "core/hid/hid_types.h"
15#include "core/hle/service/hid/controllers/controller_base.h" 13#include "core/hle/service/hid/controllers/controller_base.h"
16#include "core/hle/service/hid/ring_lifo.h" 14#include "core/hle/service/hid/controllers/types/npad_types.h"
17 15
18namespace Core::HID { 16namespace Core::HID {
19class EmulatedController; 17class EmulatedController;
@@ -32,10 +30,13 @@ class ServiceContext;
32union Result; 30union Result;
33 31
34namespace Service::HID { 32namespace Service::HID {
33struct NpadInternalState;
34struct NpadSixAxisSensorLifo;
35struct NpadSharedMemoryFormat;
35 36
36class NPad final : public ControllerBase { 37class NPad final : public ControllerBase {
37public: 38public:
38 explicit NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, 39 explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
39 KernelHelpers::ServiceContext& service_context_); 40 KernelHelpers::ServiceContext& service_context_);
40 ~NPad() override; 41 ~NPad() override;
41 42
@@ -48,89 +49,6 @@ public:
48 // When the controller is requesting an update for the shared memory 49 // When the controller is requesting an update for the shared memory
49 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 50 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
50 51
51 // This is nn::hid::NpadJoyHoldType
52 enum class NpadJoyHoldType : u64 {
53 Vertical = 0,
54 Horizontal = 1,
55 };
56
57 // This is nn::hid::NpadJoyAssignmentMode
58 enum class NpadJoyAssignmentMode : u32 {
59 Dual = 0,
60 Single = 1,
61 };
62
63 // This is nn::hid::NpadJoyDeviceType
64 enum class NpadJoyDeviceType : s64 {
65 Left = 0,
66 Right = 1,
67 };
68
69 // This is nn::hid::NpadHandheldActivationMode
70 enum class NpadHandheldActivationMode : u64 {
71 Dual = 0,
72 Single = 1,
73 None = 2,
74 MaxActivationMode = 3,
75 };
76
77 // This is nn::hid::system::AppletFooterUiAttributesSet
78 struct AppletFooterUiAttributes {
79 INSERT_PADDING_BYTES(0x4);
80 };
81
82 // This is nn::hid::system::AppletFooterUiType
83 enum class AppletFooterUiType : u8 {
84 None = 0,
85 HandheldNone = 1,
86 HandheldJoyConLeftOnly = 2,
87 HandheldJoyConRightOnly = 3,
88 HandheldJoyConLeftJoyConRight = 4,
89 JoyDual = 5,
90 JoyDualLeftOnly = 6,
91 JoyDualRightOnly = 7,
92 JoyLeftHorizontal = 8,
93 JoyLeftVertical = 9,
94 JoyRightHorizontal = 10,
95 JoyRightVertical = 11,
96 SwitchProController = 12,
97 CompatibleProController = 13,
98 CompatibleJoyCon = 14,
99 LarkHvc1 = 15,
100 LarkHvc2 = 16,
101 LarkNesLeft = 17,
102 LarkNesRight = 18,
103 Lucia = 19,
104 Verification = 20,
105 Lagon = 21,
106 };
107
108 using AppletFooterUiVariant = u8;
109
110 // This is "nn::hid::system::AppletDetailedUiType".
111 struct AppletDetailedUiType {
112 AppletFooterUiVariant ui_variant;
113 INSERT_PADDING_BYTES(0x2);
114 AppletFooterUiType footer;
115 };
116 static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
117 // This is nn::hid::NpadCommunicationMode
118 enum class NpadCommunicationMode : u64 {
119 Mode_5ms = 0,
120 Mode_10ms = 1,
121 Mode_15ms = 2,
122 Default = 3,
123 };
124
125 enum class NpadRevision : u32 {
126 Revision0 = 0,
127 Revision1 = 1,
128 Revision2 = 2,
129 Revision3 = 3,
130 };
131
132 using SixAxisLifo = Lifo<Core::HID::SixAxisSensorState, hid_entry_count>;
133
134 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); 52 void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
135 Core::HID::NpadStyleTag GetSupportedStyleSet() const; 53 Core::HID::NpadStyleTag GetSupportedStyleSet() const;
136 54
@@ -188,12 +106,12 @@ public:
188 Result ResetIsSixAxisSensorDeviceNewlyAssigned( 106 Result ResetIsSixAxisSensorDeviceNewlyAssigned(
189 const Core::HID::SixAxisSensorHandle& sixaxis_handle); 107 const Core::HID::SixAxisSensorHandle& sixaxis_handle);
190 108
191 SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id); 109 NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
192 SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id); 110 NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
193 SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id); 111 NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
194 SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id); 112 NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
195 SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id); 113 NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
196 SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id); 114 NpadSixAxisSensorLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
197 115
198 Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; 116 Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
199 Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, 117 Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
@@ -221,214 +139,6 @@ public:
221 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); 139 AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
222 140
223private: 141private:
224 static constexpr std::size_t NPAD_COUNT = 10;
225
226 // This is nn::hid::detail::ColorAttribute
227 enum class ColorAttribute : u32 {
228 Ok = 0,
229 ReadError = 1,
230 NoController = 2,
231 };
232 static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
233
234 // This is nn::hid::detail::NpadFullKeyColorState
235 struct NpadFullKeyColorState {
236 ColorAttribute attribute{ColorAttribute::NoController};
237 Core::HID::NpadControllerColor fullkey{};
238 };
239 static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
240
241 // This is nn::hid::detail::NpadJoyColorState
242 struct NpadJoyColorState {
243 ColorAttribute attribute{ColorAttribute::NoController};
244 Core::HID::NpadControllerColor left{};
245 Core::HID::NpadControllerColor right{};
246 };
247 static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
248
249 // This is nn::hid::NpadAttribute
250 struct NpadAttribute {
251 union {
252 u32 raw{};
253 BitField<0, 1, u32> is_connected;
254 BitField<1, 1, u32> is_wired;
255 BitField<2, 1, u32> is_left_connected;
256 BitField<3, 1, u32> is_left_wired;
257 BitField<4, 1, u32> is_right_connected;
258 BitField<5, 1, u32> is_right_wired;
259 };
260 };
261 static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
262
263 // This is nn::hid::NpadFullKeyState
264 // This is nn::hid::NpadHandheldState
265 // This is nn::hid::NpadJoyDualState
266 // This is nn::hid::NpadJoyLeftState
267 // This is nn::hid::NpadJoyRightState
268 // This is nn::hid::NpadPalmaState
269 // This is nn::hid::NpadSystemExtState
270 struct NPadGenericState {
271 s64_le sampling_number{};
272 Core::HID::NpadButtonState npad_buttons{};
273 Core::HID::AnalogStickState l_stick{};
274 Core::HID::AnalogStickState r_stick{};
275 NpadAttribute connection_status{};
276 INSERT_PADDING_BYTES(4); // Reserved
277 };
278 static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
279
280 // This is nn::hid::server::NpadGcTriggerState
281 struct NpadGcTriggerState {
282 s64 sampling_number{};
283 s32 l_analog{};
284 s32 r_analog{};
285 };
286 static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
287
288 // This is nn::hid::NpadSystemProperties
289 struct NPadSystemProperties {
290 union {
291 s64 raw{};
292 BitField<0, 1, s64> is_charging_joy_dual;
293 BitField<1, 1, s64> is_charging_joy_left;
294 BitField<2, 1, s64> is_charging_joy_right;
295 BitField<3, 1, s64> is_powered_joy_dual;
296 BitField<4, 1, s64> is_powered_joy_left;
297 BitField<5, 1, s64> is_powered_joy_right;
298 BitField<9, 1, s64> is_system_unsupported_button;
299 BitField<10, 1, s64> is_system_ext_unsupported_button;
300 BitField<11, 1, s64> is_vertical;
301 BitField<12, 1, s64> is_horizontal;
302 BitField<13, 1, s64> use_plus;
303 BitField<14, 1, s64> use_minus;
304 BitField<15, 1, s64> use_directional_buttons;
305 };
306 };
307 static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
308
309 // This is nn::hid::NpadSystemButtonProperties
310 struct NpadSystemButtonProperties {
311 union {
312 s32 raw{};
313 BitField<0, 1, s32> is_home_button_protection_enabled;
314 };
315 };
316 static_assert(sizeof(NpadSystemButtonProperties) == 0x4,
317 "NPadButtonProperties is an invalid size");
318
319 // This is nn::hid::system::DeviceType
320 struct DeviceType {
321 union {
322 u32 raw{};
323 BitField<0, 1, s32> fullkey;
324 BitField<1, 1, s32> debug_pad;
325 BitField<2, 1, s32> handheld_left;
326 BitField<3, 1, s32> handheld_right;
327 BitField<4, 1, s32> joycon_left;
328 BitField<5, 1, s32> joycon_right;
329 BitField<6, 1, s32> palma;
330 BitField<7, 1, s32> lark_hvc_left;
331 BitField<8, 1, s32> lark_hvc_right;
332 BitField<9, 1, s32> lark_nes_left;
333 BitField<10, 1, s32> lark_nes_right;
334 BitField<11, 1, s32> handheld_lark_hvc_left;
335 BitField<12, 1, s32> handheld_lark_hvc_right;
336 BitField<13, 1, s32> handheld_lark_nes_left;
337 BitField<14, 1, s32> handheld_lark_nes_right;
338 BitField<15, 1, s32> lucia;
339 BitField<16, 1, s32> lagon;
340 BitField<17, 1, s32> lager;
341 BitField<31, 1, s32> system;
342 };
343 };
344
345 // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
346 struct NfcXcdDeviceHandleStateImpl {
347 u64 handle{};
348 bool is_available{};
349 bool is_activated{};
350 INSERT_PADDING_BYTES(0x6); // Reserved
351 u64 sampling_number{};
352 };
353 static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
354 "NfcXcdDeviceHandleStateImpl is an invalid size");
355
356 // This is nn::hid::NpadLarkType
357 enum class NpadLarkType : u32 {
358 Invalid,
359 H1,
360 H2,
361 NL,
362 NR,
363 };
364
365 // This is nn::hid::NpadLuciaType
366 enum class NpadLuciaType : u32 {
367 Invalid,
368 J,
369 E,
370 U,
371 };
372
373 // This is nn::hid::NpadLagonType
374 enum class NpadLagonType : u32 {
375 Invalid,
376 };
377
378 // This is nn::hid::NpadLagerType
379 enum class NpadLagerType : u32 {
380 Invalid,
381 J,
382 E,
383 U,
384 };
385
386 // This is nn::hid::detail::NpadInternalState
387 struct NpadInternalState {
388 Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
389 NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
390 NpadFullKeyColorState fullkey_color{};
391 NpadJoyColorState joycon_color{};
392 Lifo<NPadGenericState, hid_entry_count> fullkey_lifo{};
393 Lifo<NPadGenericState, hid_entry_count> handheld_lifo{};
394 Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo{};
395 Lifo<NPadGenericState, hid_entry_count> joy_left_lifo{};
396 Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{};
397 Lifo<NPadGenericState, hid_entry_count> palma_lifo{};
398 Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{};
399 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{};
400 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{};
401 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{};
402 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{};
403 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{};
404 Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{};
405 DeviceType device_type{};
406 INSERT_PADDING_BYTES(0x4); // Reserved
407 NPadSystemProperties system_properties{};
408 NpadSystemButtonProperties button_properties{};
409 Core::HID::NpadBatteryLevel battery_level_dual{};
410 Core::HID::NpadBatteryLevel battery_level_left{};
411 Core::HID::NpadBatteryLevel battery_level_right{};
412 AppletFooterUiAttributes applet_footer_attributes{};
413 AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
414 INSERT_PADDING_BYTES(0x5B); // Reserved
415 INSERT_PADDING_BYTES(0x20); // Unknown
416 Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{};
417 NpadLarkType lark_type_l_and_main{};
418 NpadLarkType lark_type_r{};
419 NpadLuciaType lucia_type{};
420 NpadLagonType lagon_type{};
421 NpadLagerType lager_type{};
422 Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
423 Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
424 Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
425 Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
426 Core::HID::SixAxisSensorProperties sixaxis_left_properties;
427 Core::HID::SixAxisSensorProperties sixaxis_right_properties;
428 INSERT_PADDING_BYTES(0xc06); // Unknown
429 };
430 static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
431
432 struct VibrationData { 142 struct VibrationData {
433 bool device_mounted{}; 143 bool device_mounted{};
434 Core::HID::VibrationValue latest_vibration_value{}; 144 Core::HID::VibrationValue latest_vibration_value{};
@@ -479,7 +189,7 @@ private:
479 189
480 std::atomic<u64> press_state{}; 190 std::atomic<u64> press_state{};
481 191
482 std::array<NpadControllerData, NPAD_COUNT> controller_data{}; 192 std::array<NpadControllerData, NpadCount> controller_data{};
483 KernelHelpers::ServiceContext& service_context; 193 KernelHelpers::ServiceContext& service_context;
484 std::mutex mutex; 194 std::mutex mutex;
485 std::vector<Core::HID::NpadIdType> supported_npad_id_types{}; 195 std::vector<Core::HID::NpadIdType> supported_npad_id_types{};
diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp
index 588ff9d62..aa0454b5e 100644
--- a/src/core/hle/service/hid/controllers/palma.cpp
+++ b/src/core/hle/service/hid/controllers/palma.cpp
@@ -12,8 +12,7 @@
12 12
13namespace Service::HID { 13namespace Service::HID {
14 14
15Palma::Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, 15Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
16 KernelHelpers::ServiceContext& service_context_)
17 : ControllerBase{hid_core_}, service_context{service_context_} { 16 : ControllerBase{hid_core_}, service_context{service_context_} {
18 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); 17 controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
19 operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent"); 18 operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");
diff --git a/src/core/hle/service/hid/controllers/palma.h b/src/core/hle/service/hid/controllers/palma.h
index a6047f36a..73884230d 100644
--- a/src/core/hle/service/hid/controllers/palma.h
+++ b/src/core/hle/service/hid/controllers/palma.h
@@ -97,8 +97,7 @@ public:
97 static_assert(sizeof(PalmaConnectionHandle) == 0x8, 97 static_assert(sizeof(PalmaConnectionHandle) == 0x8,
98 "PalmaConnectionHandle has incorrect size."); 98 "PalmaConnectionHandle has incorrect size.");
99 99
100 explicit Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, 100 explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
101 KernelHelpers::ServiceContext& service_context_);
102 ~Palma() override; 101 ~Palma() override;
103 102
104 // Called when the controller is initialized 103 // Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/shared_memory_format.h b/src/core/hle/service/hid/controllers/shared_memory_format.h
new file mode 100644
index 000000000..2986c113e
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_format.h
@@ -0,0 +1,240 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_funcs.h"
7#include "common/common_types.h"
8#include "common/vector_math.h"
9#include "core/hid/hid_types.h"
10#include "core/hle/service/hid//controllers/types/debug_pad_types.h"
11#include "core/hle/service/hid//controllers/types/keyboard_types.h"
12#include "core/hle/service/hid//controllers/types/mouse_types.h"
13#include "core/hle/service/hid//controllers/types/npad_types.h"
14#include "core/hle/service/hid//controllers/types/touch_types.h"
15#include "core/hle/service/hid/ring_lifo.h"
16
17namespace Service::HID {
18static const std::size_t HidEntryCount = 17;
19
20struct CommonHeader {
21 s64 timestamp{};
22 s64 total_entry_count{};
23 s64 last_entry_index{};
24 s64 entry_count{};
25};
26static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
27
28// This is nn::hid::detail::DebugPadSharedMemoryFormat
29struct DebugPadSharedMemoryFormat {
30 // This is nn::hid::detail::DebugPadLifo
31 Lifo<DebugPadState, HidEntryCount> debug_pad_lifo{};
32 static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
33 INSERT_PADDING_WORDS(0x4E);
34};
35static_assert(sizeof(DebugPadSharedMemoryFormat) == 0x400,
36 "DebugPadSharedMemoryFormat is an invalid size");
37
38// This is nn::hid::detail::TouchScreenSharedMemoryFormat
39struct TouchScreenSharedMemoryFormat {
40 // This is nn::hid::detail::TouchScreenLifo
41 Lifo<TouchScreenState, HidEntryCount> touch_screen_lifo{};
42 static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
43 INSERT_PADDING_WORDS(0xF2);
44};
45static_assert(sizeof(TouchScreenSharedMemoryFormat) == 0x3000,
46 "TouchScreenSharedMemoryFormat is an invalid size");
47
48// This is nn::hid::detail::MouseSharedMemoryFormat
49struct MouseSharedMemoryFormat {
50 // This is nn::hid::detail::MouseLifo
51 Lifo<Core::HID::MouseState, HidEntryCount> mouse_lifo{};
52 static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
53 INSERT_PADDING_WORDS(0x2C);
54};
55static_assert(sizeof(MouseSharedMemoryFormat) == 0x400,
56 "MouseSharedMemoryFormat is an invalid size");
57
58// This is nn::hid::detail::KeyboardSharedMemoryFormat
59struct KeyboardSharedMemoryFormat {
60 // This is nn::hid::detail::KeyboardLifo
61 Lifo<KeyboardState, HidEntryCount> keyboard_lifo{};
62 static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
63 INSERT_PADDING_WORDS(0xA);
64};
65static_assert(sizeof(KeyboardSharedMemoryFormat) == 0x400,
66 "KeyboardSharedMemoryFormat is an invalid size");
67
68// This is nn::hid::detail::DigitizerSharedMemoryFormat
69struct DigitizerSharedMemoryFormat {
70 CommonHeader header;
71 INSERT_PADDING_BYTES(0xFE0);
72};
73static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000,
74 "DigitizerSharedMemoryFormat is an invalid size");
75
76// This is nn::hid::detail::HomeButtonSharedMemoryFormat
77struct HomeButtonSharedMemoryFormat {
78 CommonHeader header;
79 INSERT_PADDING_BYTES(0x1E0);
80};
81static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200,
82 "HomeButtonSharedMemoryFormat is an invalid size");
83
84// This is nn::hid::detail::SleepButtonSharedMemoryFormat
85struct SleepButtonSharedMemoryFormat {
86 CommonHeader header;
87 INSERT_PADDING_BYTES(0x1E0);
88};
89static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200,
90 "SleepButtonSharedMemoryFormat is an invalid size");
91
92// This is nn::hid::detail::CaptureButtonSharedMemoryFormat
93struct CaptureButtonSharedMemoryFormat {
94 CommonHeader header;
95 INSERT_PADDING_BYTES(0x1E0);
96};
97static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200,
98 "CaptureButtonSharedMemoryFormat is an invalid size");
99
100// This is nn::hid::detail::InputDetectorSharedMemoryFormat
101struct InputDetectorSharedMemoryFormat {
102 CommonHeader header;
103 INSERT_PADDING_BYTES(0x7E0);
104};
105static_assert(sizeof(InputDetectorSharedMemoryFormat) == 0x800,
106 "InputDetectorSharedMemoryFormat is an invalid size");
107
108// This is nn::hid::detail::UniquePadSharedMemoryFormat
109struct UniquePadSharedMemoryFormat {
110 CommonHeader header;
111 INSERT_PADDING_BYTES(0x3FE0);
112};
113static_assert(sizeof(UniquePadSharedMemoryFormat) == 0x4000,
114 "UniquePadSharedMemoryFormat is an invalid size");
115
116// This is nn::hid::detail::NpadSixAxisSensorLifo
117struct NpadSixAxisSensorLifo {
118 Lifo<Core::HID::SixAxisSensorState, HidEntryCount> lifo;
119};
120
121// This is nn::hid::detail::NpadInternalState
122struct NpadInternalState {
123 Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
124 NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
125 NpadFullKeyColorState fullkey_color{};
126 NpadJoyColorState joycon_color{};
127 Lifo<NPadGenericState, HidEntryCount> fullkey_lifo{};
128 Lifo<NPadGenericState, HidEntryCount> handheld_lifo{};
129 Lifo<NPadGenericState, HidEntryCount> joy_dual_lifo{};
130 Lifo<NPadGenericState, HidEntryCount> joy_left_lifo{};
131 Lifo<NPadGenericState, HidEntryCount> joy_right_lifo{};
132 Lifo<NPadGenericState, HidEntryCount> palma_lifo{};
133 Lifo<NPadGenericState, HidEntryCount> system_ext_lifo{};
134 NpadSixAxisSensorLifo sixaxis_fullkey_lifo{};
135 NpadSixAxisSensorLifo sixaxis_handheld_lifo{};
136 NpadSixAxisSensorLifo sixaxis_dual_left_lifo{};
137 NpadSixAxisSensorLifo sixaxis_dual_right_lifo{};
138 NpadSixAxisSensorLifo sixaxis_left_lifo{};
139 NpadSixAxisSensorLifo sixaxis_right_lifo{};
140 DeviceType device_type{};
141 INSERT_PADDING_BYTES(0x4); // Reserved
142 NPadSystemProperties system_properties{};
143 NpadSystemButtonProperties button_properties{};
144 Core::HID::NpadBatteryLevel battery_level_dual{};
145 Core::HID::NpadBatteryLevel battery_level_left{};
146 Core::HID::NpadBatteryLevel battery_level_right{};
147 AppletFooterUiAttributes applet_footer_attributes{};
148 AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
149 INSERT_PADDING_BYTES(0x5B); // Reserved
150 INSERT_PADDING_BYTES(0x20); // Unknown
151 Lifo<NpadGcTriggerState, HidEntryCount> gc_trigger_lifo{};
152 NpadLarkType lark_type_l_and_main{};
153 NpadLarkType lark_type_r{};
154 NpadLuciaType lucia_type{};
155 NpadLagerType lager_type{};
156 Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
157 Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
158 Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
159 Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
160 Core::HID::SixAxisSensorProperties sixaxis_left_properties;
161 Core::HID::SixAxisSensorProperties sixaxis_right_properties;
162};
163static_assert(sizeof(NpadInternalState) == 0x43F8, "NpadInternalState is an invalid size");
164
165// This is nn::hid::detail::NpadSharedMemoryEntry
166struct NpadSharedMemoryEntry {
167 NpadInternalState internal_state;
168 INSERT_PADDING_BYTES(0xC08);
169};
170static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is an invalid size");
171
172// This is nn::hid::detail::NpadSharedMemoryFormat
173struct NpadSharedMemoryFormat {
174 std::array<NpadSharedMemoryEntry, NpadCount> npad_entry;
175};
176static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000,
177 "NpadSharedMemoryFormat is an invalid size");
178
179// This is nn::hid::detail::GestureSharedMemoryFormat
180struct GestureSharedMemoryFormat {
181 // This is nn::hid::detail::GestureLifo
182 Lifo<GestureState, HidEntryCount> gesture_lifo{};
183 static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
184 INSERT_PADDING_WORDS(0x3E);
185};
186static_assert(sizeof(GestureSharedMemoryFormat) == 0x800,
187 "GestureSharedMemoryFormat is an invalid size");
188
189// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
190struct ConsoleSixAxisSensorSharedMemoryFormat {
191 u64 sampling_number{};
192 bool is_seven_six_axis_sensor_at_rest{};
193 INSERT_PADDING_BYTES(3); // padding
194 f32 verticalization_error{};
195 Common::Vec3f gyro_bias{};
196 INSERT_PADDING_BYTES(4); // padding
197};
198static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20,
199 "ConsoleSixAxisSensorSharedMemoryFormat is an invalid size");
200
201// This is nn::hid::detail::SharedMemoryFormat
202struct SharedMemoryFormat {
203 void Initialize() {}
204
205 DebugPadSharedMemoryFormat debug_pad;
206 TouchScreenSharedMemoryFormat touch_screen;
207 MouseSharedMemoryFormat mouse;
208 KeyboardSharedMemoryFormat keyboard;
209 DigitizerSharedMemoryFormat digitizer;
210 HomeButtonSharedMemoryFormat home_button;
211 SleepButtonSharedMemoryFormat sleep_button;
212 CaptureButtonSharedMemoryFormat capture_button;
213 InputDetectorSharedMemoryFormat input_detector;
214 UniquePadSharedMemoryFormat unique_pad;
215 NpadSharedMemoryFormat npad;
216 GestureSharedMemoryFormat gesture;
217 ConsoleSixAxisSensorSharedMemoryFormat console;
218 INSERT_PADDING_BYTES(0x19E0);
219 MouseSharedMemoryFormat debug_mouse;
220 INSERT_PADDING_BYTES(0x2000);
221};
222static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
223static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
224static_assert(offsetof(SharedMemoryFormat, mouse) == 0x3400, "mouse has wrong offset");
225static_assert(offsetof(SharedMemoryFormat, keyboard) == 0x3800, "keyboard has wrong offset");
226static_assert(offsetof(SharedMemoryFormat, digitizer) == 0x3C00, "digitizer has wrong offset");
227static_assert(offsetof(SharedMemoryFormat, home_button) == 0x4C00, "home_button has wrong offset");
228static_assert(offsetof(SharedMemoryFormat, sleep_button) == 0x4E00,
229 "sleep_button has wrong offset");
230static_assert(offsetof(SharedMemoryFormat, capture_button) == 0x5000,
231 "capture_button has wrong offset");
232static_assert(offsetof(SharedMemoryFormat, input_detector) == 0x5200,
233 "input_detector has wrong offset");
234static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offset");
235static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
236static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
237static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
238static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
239
240} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp
new file mode 100644
index 000000000..51581188e
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp
@@ -0,0 +1,53 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/core.h"
5#include "core/hle/kernel/k_shared_memory.h"
6#include "core/hle/service/hid/controllers/shared_memory_format.h"
7#include "core/hle/service/hid/controllers/shared_memory_holder.h"
8#include "core/hle/service/hid/errors.h"
9
10namespace Service::HID {
11SharedMemoryHolder::SharedMemoryHolder() {}
12
13SharedMemoryHolder::~SharedMemoryHolder() {
14 Finalize();
15}
16
17Result SharedMemoryHolder::Initialize(Core::System& system) {
18 shared_memory = Kernel::KSharedMemory::Create(system.Kernel());
19 const Result result = shared_memory->Initialize(
20 system.DeviceMemory(), nullptr, Kernel::Svc::MemoryPermission::None,
21 Kernel::Svc::MemoryPermission::Read, sizeof(SharedMemoryFormat));
22 if (result.IsError()) {
23 return result;
24 }
25 Kernel::KSharedMemory::Register(system.Kernel(), shared_memory);
26
27 is_created = true;
28 is_mapped = true;
29 address = std::construct_at(reinterpret_cast<SharedMemoryFormat*>(shared_memory->GetPointer()));
30 return ResultSuccess;
31}
32
33void SharedMemoryHolder::Finalize() {
34 if (address != nullptr) {
35 shared_memory->Close();
36 }
37 is_created = false;
38 is_mapped = false;
39 address = nullptr;
40}
41
42bool SharedMemoryHolder::IsMapped() {
43 return is_mapped;
44}
45
46SharedMemoryFormat* SharedMemoryHolder::GetAddress() {
47 return address;
48}
49
50Kernel::KSharedMemory* SharedMemoryHolder::GetHandle() {
51 return shared_memory;
52}
53} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.h b/src/core/hle/service/hid/controllers/shared_memory_holder.h
new file mode 100644
index 000000000..943407c00
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_holder.h
@@ -0,0 +1,44 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Core {
9class System;
10}
11
12namespace Kernel {
13class KSharedMemory;
14}
15
16namespace Service::HID {
17struct SharedMemoryFormat;
18
19// This is nn::hid::detail::SharedMemoryHolder
20class SharedMemoryHolder {
21public:
22 SharedMemoryHolder();
23 ~SharedMemoryHolder();
24
25 Result Initialize(Core::System& system);
26 void Finalize();
27
28 bool IsMapped();
29 SharedMemoryFormat* GetAddress();
30 Kernel::KSharedMemory* GetHandle();
31
32private:
33 bool is_owner{};
34 bool is_created{};
35 bool is_mapped{};
36 INSERT_PADDING_BYTES(0x5);
37 Kernel::KSharedMemory* shared_memory;
38 INSERT_PADDING_BYTES(0x38);
39 SharedMemoryFormat* address = nullptr;
40};
41// Correct size is 0x50 bytes
42static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size");
43
44} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/six_axis.cpp b/src/core/hle/service/hid/controllers/six_axis.cpp
index 3d24a5c04..36b72f9ea 100644
--- a/src/core/hle/service/hid/controllers/six_axis.cpp
+++ b/src/core/hle/service/hid/controllers/six_axis.cpp
@@ -6,6 +6,7 @@
6#include "core/hid/emulated_controller.h" 6#include "core/hid/emulated_controller.h"
7#include "core/hid/hid_core.h" 7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/npad.h" 8#include "core/hle/service/hid/controllers/npad.h"
9#include "core/hle/service/hid/controllers/shared_memory_format.h"
9#include "core/hle/service/hid/controllers/six_axis.h" 10#include "core/hle/service/hid/controllers/six_axis.h"
10#include "core/hle/service/hid/errors.h" 11#include "core/hle/service/hid/errors.h"
11#include "core/hle/service/hid/hid_util.h" 12#include "core/hle/service/hid/hid_util.h"
@@ -132,30 +133,30 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
132 } 133 }
133 134
134 sixaxis_fullkey_state.sampling_number = 135 sixaxis_fullkey_state.sampling_number =
135 sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; 136 sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
136 sixaxis_handheld_state.sampling_number = 137 sixaxis_handheld_state.sampling_number =
137 sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; 138 sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
138 sixaxis_dual_left_state.sampling_number = 139 sixaxis_dual_left_state.sampling_number =
139 sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; 140 sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
140 sixaxis_dual_right_state.sampling_number = 141 sixaxis_dual_right_state.sampling_number =
141 sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; 142 sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
142 sixaxis_left_lifo_state.sampling_number = 143 sixaxis_left_lifo_state.sampling_number =
143 sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; 144 sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
144 sixaxis_right_lifo_state.sampling_number = 145 sixaxis_right_lifo_state.sampling_number =
145 sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; 146 sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
146 147
147 if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { 148 if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
148 // This buffer only is updated on handheld on HW 149 // This buffer only is updated on handheld on HW
149 sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); 150 sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
150 } else { 151 } else {
151 // Handheld doesn't update this buffer on HW 152 // Handheld doesn't update this buffer on HW
152 sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); 153 sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
153 } 154 }
154 155
155 sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); 156 sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
156 sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); 157 sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
157 sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); 158 sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
158 sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); 159 sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
159 } 160 }
160} 161}
161 162
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index 9e2f3ab21..e2a5f5d79 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -1,18 +1,15 @@
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 <cstring>
5#include "common/common_types.h"
6#include "core/core_timing.h" 4#include "core/core_timing.h"
7#include "core/hid/hid_core.h" 5#include "core/hle/service/hid/controllers/shared_memory_format.h"
8#include "core/hle/service/hid/controllers/stubbed.h" 6#include "core/hle/service/hid/controllers/stubbed.h"
9 7
10namespace Service::HID { 8namespace Service::HID {
11 9
12Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 10Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_,
13 : ControllerBase{hid_core_} { 11 CommonHeader& ring_lifo_header)
14 raw_shared_memory = raw_shared_memory_; 12 : ControllerBase{hid_core_}, header{ring_lifo_header} {}
15}
16 13
17Controller_Stubbed::~Controller_Stubbed() = default; 14Controller_Stubbed::~Controller_Stubbed() = default;
18 15
@@ -25,18 +22,10 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
25 return; 22 return;
26 } 23 }
27 24
28 CommonHeader header{};
29 header.timestamp = core_timing.GetGlobalTimeNs().count(); 25 header.timestamp = core_timing.GetGlobalTimeNs().count();
30 header.total_entry_count = 17; 26 header.total_entry_count = 17;
31 header.entry_count = 0; 27 header.entry_count = 0;
32 header.last_entry_index = 0; 28 header.last_entry_index = 0;
33
34 std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader));
35}
36
37void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
38 common_offset = off;
39 smart_update = true;
40} 29}
41 30
42} // namespace Service::HID 31} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 1483a968e..d2052fb17 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -3,13 +3,14 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_types.h"
7#include "core/hle/service/hid/controllers/controller_base.h" 6#include "core/hle/service/hid/controllers/controller_base.h"
8 7
9namespace Service::HID { 8namespace Service::HID {
9struct CommonHeader;
10
10class Controller_Stubbed final : public ControllerBase { 11class Controller_Stubbed final : public ControllerBase {
11public: 12public:
12 explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 13 explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, CommonHeader& ring_lifo_header);
13 ~Controller_Stubbed() override; 14 ~Controller_Stubbed() override;
14 15
15 // Called when the controller is initialized 16 // Called when the controller is initialized
@@ -21,19 +22,8 @@ public:
21 // When the controller is requesting an update for the shared memory 22 // When the controller is requesting an update for the shared memory
22 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; 23 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
23 24
24 void SetCommonHeaderOffset(std::size_t off);
25
26private: 25private:
27 struct CommonHeader { 26 CommonHeader& header;
28 s64 timestamp{};
29 s64 total_entry_count{};
30 s64 last_entry_index{};
31 s64 entry_count{};
32 };
33 static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
34
35 u8* raw_shared_memory = nullptr;
36 bool smart_update{}; 27 bool smart_update{};
37 std::size_t common_offset{};
38}; 28};
39} // namespace Service::HID 29} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index fcd973414..469750006 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -2,26 +2,22 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <algorithm> 4#include <algorithm>
5#include <cstring>
6#include "common/common_types.h" 5#include "common/common_types.h"
7#include "common/settings.h" 6#include "common/settings.h"
8#include "core/core.h"
9#include "core/core_timing.h" 7#include "core/core_timing.h"
10#include "core/frontend/emu_window.h" 8#include "core/frontend/emu_window.h"
11#include "core/hid/emulated_console.h" 9#include "core/hid/emulated_console.h"
12#include "core/hid/hid_core.h" 10#include "core/hid/hid_core.h"
11#include "core/hle/service/hid/controllers/shared_memory_format.h"
13#include "core/hle/service/hid/controllers/touchscreen.h" 12#include "core/hle/service/hid/controllers/touchscreen.h"
14 13
15namespace Service::HID { 14namespace Service::HID {
16constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
17 15
18TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) 16TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_,
19 : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width), 17 TouchScreenSharedMemoryFormat& touch_shared_memory)
18 : ControllerBase{hid_core_}, shared_memory{touch_shared_memory},
19 touchscreen_width(Layout::ScreenUndocked::Width),
20 touchscreen_height(Layout::ScreenUndocked::Height) { 20 touchscreen_height(Layout::ScreenUndocked::Height) {
21 static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
22 "TouchSharedMemory is bigger than the shared memory");
23 shared_memory = std::construct_at(
24 reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
25 console = hid_core.GetEmulatedConsole(); 21 console = hid_core.GetEmulatedConsole();
26} 22}
27 23
@@ -32,11 +28,11 @@ void TouchScreen::OnInit() {}
32void TouchScreen::OnRelease() {} 28void TouchScreen::OnRelease() {}
33 29
34void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { 30void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
35 shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); 31 shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
36 32
37 if (!IsControllerActivated()) { 33 if (!IsControllerActivated()) {
38 shared_memory->touch_screen_lifo.buffer_count = 0; 34 shared_memory.touch_screen_lifo.buffer_count = 0;
39 shared_memory->touch_screen_lifo.buffer_tail = 0; 35 shared_memory.touch_screen_lifo.buffer_tail = 0;
40 return; 36 return;
41 } 37 }
42 38
@@ -86,7 +82,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
86 static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); 82 static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
87 83
88 const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count()); 84 const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
89 const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state; 85 const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state;
90 86
91 next_state.sampling_number = last_entry.sampling_number + 1; 87 next_state.sampling_number = last_entry.sampling_number + 1;
92 next_state.entry_count = static_cast<s32>(active_fingers_count); 88 next_state.entry_count = static_cast<s32>(active_fingers_count);
@@ -118,7 +114,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
118 } 114 }
119 } 115 }
120 116
121 shared_memory->touch_screen_lifo.WriteNextEntry(next_state); 117 shared_memory.touch_screen_lifo.WriteNextEntry(next_state);
122} 118}
123 119
124void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) { 120void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) {
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 79f026a81..5b6305bfc 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -3,20 +3,23 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "common/common_funcs.h" 6#include <array>
7#include "common/common_types.h" 7
8#include "core/hid/hid_types.h" 8#include "core/hid/hid_types.h"
9#include "core/hle/service/hid/controllers/controller_base.h" 9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/hid/ring_lifo.h" 10#include "core/hle/service/hid/controllers/types/touch_types.h"
11 11
12namespace Core::HID { 12namespace Core::HID {
13class EmulatedConsole; 13class EmulatedConsole;
14} // namespace Core::HID 14} // namespace Core::HID
15 15
16namespace Service::HID { 16namespace Service::HID {
17struct TouchScreenSharedMemoryFormat;
18
17class TouchScreen final : public ControllerBase { 19class TouchScreen final : public ControllerBase {
18public: 20public:
19 explicit TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); 21 explicit TouchScreen(Core::HID::HIDCore& hid_core_,
22 TouchScreenSharedMemoryFormat& touch_shared_memory);
20 ~TouchScreen() override; 23 ~TouchScreen() override;
21 24
22 // Called when the controller is initialized 25 // Called when the controller is initialized
@@ -31,27 +34,8 @@ public:
31 void SetTouchscreenDimensions(u32 width, u32 height); 34 void SetTouchscreenDimensions(u32 width, u32 height);
32 35
33private: 36private:
34 static constexpr std::size_t MAX_FINGERS = 16;
35
36 // This is nn::hid::TouchScreenState
37 struct TouchScreenState {
38 s64 sampling_number{};
39 s32 entry_count{};
40 INSERT_PADDING_BYTES(4); // Reserved
41 std::array<Core::HID::TouchState, MAX_FINGERS> states{};
42 };
43 static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
44
45 struct TouchSharedMemory {
46 // This is nn::hid::detail::TouchScreenLifo
47 Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{};
48 static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
49 INSERT_PADDING_WORDS(0xF2);
50 };
51 static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size");
52
53 TouchScreenState next_state{}; 37 TouchScreenState next_state{};
54 TouchSharedMemory* shared_memory = nullptr; 38 TouchScreenSharedMemoryFormat& shared_memory;
55 Core::HID::EmulatedConsole* console = nullptr; 39 Core::HID::EmulatedConsole* console = nullptr;
56 40
57 std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; 41 std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
diff --git a/src/core/hle/service/hid/controllers/types/debug_pad_types.h b/src/core/hle/service/hid/controllers/types/debug_pad_types.h
new file mode 100644
index 000000000..a96171b62
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/debug_pad_types.h
@@ -0,0 +1,31 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_types.h"
8#include "core/hid/hid_types.h"
9
10namespace Service::HID {
11
12// This is nn::hid::DebugPadAttribute
13struct DebugPadAttribute {
14 union {
15 u32 raw{};
16 BitField<0, 1, u32> connected;
17 };
18};
19static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
20
21// This is nn::hid::DebugPadState
22struct DebugPadState {
23 s64 sampling_number{};
24 DebugPadAttribute attribute{};
25 Core::HID::DebugPadButton pad_state{};
26 Core::HID::AnalogStickState r_stick{};
27 Core::HID::AnalogStickState l_stick{};
28};
29static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
30
31} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/gesture_types.h b/src/core/hle/service/hid/controllers/types/gesture_types.h
new file mode 100644
index 000000000..b4f034cd3
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/gesture_types.h
@@ -0,0 +1,77 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7#include "common/bit_field.h"
8#include "common/common_types.h"
9#include "common/point.h"
10
11namespace Service::HID {
12static constexpr size_t MAX_FINGERS = 16;
13static constexpr size_t MAX_POINTS = 4;
14
15// This is nn::hid::GestureType
16enum class GestureType : u32 {
17 Idle, // Nothing touching the screen
18 Complete, // Set at the end of a touch event
19 Cancel, // Set when the number of fingers change
20 Touch, // A finger just touched the screen
21 Press, // Set if last type is touch and the finger hasn't moved
22 Tap, // Fast press then release
23 Pan, // All points moving together across the screen
24 Swipe, // Fast press movement and release of a single point
25 Pinch, // All points moving away/closer to the midpoint
26 Rotate, // All points rotating from the midpoint
27};
28
29// This is nn::hid::GestureDirection
30enum class GestureDirection : u32 {
31 None,
32 Left,
33 Up,
34 Right,
35 Down,
36};
37
38// This is nn::hid::GestureAttribute
39struct GestureAttribute {
40 union {
41 u32 raw{};
42
43 BitField<4, 1, u32> is_new_touch;
44 BitField<8, 1, u32> is_double_tap;
45 };
46};
47static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
48
49// This is nn::hid::GestureState
50struct GestureState {
51 s64 sampling_number{};
52 s64 detection_count{};
53 GestureType type{GestureType::Idle};
54 GestureDirection direction{GestureDirection::None};
55 Common::Point<s32> pos{};
56 Common::Point<s32> delta{};
57 f32 vel_x{};
58 f32 vel_y{};
59 GestureAttribute attributes{};
60 f32 scale{};
61 f32 rotation_angle{};
62 s32 point_count{};
63 std::array<Common::Point<s32>, 4> points{};
64};
65static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
66
67struct GestureProperties {
68 std::array<Common::Point<s32>, MAX_POINTS> points{};
69 std::size_t active_points{};
70 Common::Point<s32> mid_point{};
71 s64 detection_count{};
72 u64 delta_time{};
73 f32 average_distance{};
74 f32 angle{};
75};
76
77} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/keyboard_types.h b/src/core/hle/service/hid/controllers/types/keyboard_types.h
new file mode 100644
index 000000000..f44a536b9
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/keyboard_types.h
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7#include "core/hid/hid_types.h"
8
9namespace Service::HID {
10
11// This is nn::hid::detail::KeyboardState
12struct KeyboardState {
13 s64 sampling_number{};
14 Core::HID::KeyboardModifier modifier{};
15 Core::HID::KeyboardAttribute attribute{};
16 Core::HID::KeyboardKey key{};
17};
18static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
19
20} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/mouse_types.h b/src/core/hle/service/hid/controllers/types/mouse_types.h
new file mode 100644
index 000000000..8bd6e167c
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/mouse_types.h
@@ -0,0 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/common_types.h"
7
8namespace Service::HID {} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/npad_types.h b/src/core/hle/service/hid/controllers/types/npad_types.h
new file mode 100644
index 000000000..a5ce2562b
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/npad_types.h
@@ -0,0 +1,254 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "common/bit_field.h"
7#include "common/common_funcs.h"
8#include "common/common_types.h"
9#include "core/hid/hid_types.h"
10
11namespace Service::HID {
12static constexpr std::size_t NpadCount = 10;
13
14// This is nn::hid::NpadJoyHoldType
15enum class NpadJoyHoldType : u64 {
16 Vertical = 0,
17 Horizontal = 1,
18};
19
20// This is nn::hid::NpadJoyAssignmentMode
21enum class NpadJoyAssignmentMode : u32 {
22 Dual = 0,
23 Single = 1,
24};
25
26// This is nn::hid::NpadJoyDeviceType
27enum class NpadJoyDeviceType : s64 {
28 Left = 0,
29 Right = 1,
30};
31
32// This is nn::hid::NpadHandheldActivationMode
33enum class NpadHandheldActivationMode : u64 {
34 Dual = 0,
35 Single = 1,
36 None = 2,
37 MaxActivationMode = 3,
38};
39
40// This is nn::hid::system::AppletFooterUiAttributesSet
41struct AppletFooterUiAttributes {
42 INSERT_PADDING_BYTES(0x4);
43};
44
45// This is nn::hid::system::AppletFooterUiType
46enum class AppletFooterUiType : u8 {
47 None = 0,
48 HandheldNone = 1,
49 HandheldJoyConLeftOnly = 2,
50 HandheldJoyConRightOnly = 3,
51 HandheldJoyConLeftJoyConRight = 4,
52 JoyDual = 5,
53 JoyDualLeftOnly = 6,
54 JoyDualRightOnly = 7,
55 JoyLeftHorizontal = 8,
56 JoyLeftVertical = 9,
57 JoyRightHorizontal = 10,
58 JoyRightVertical = 11,
59 SwitchProController = 12,
60 CompatibleProController = 13,
61 CompatibleJoyCon = 14,
62 LarkHvc1 = 15,
63 LarkHvc2 = 16,
64 LarkNesLeft = 17,
65 LarkNesRight = 18,
66 Lucia = 19,
67 Verification = 20,
68 Lagon = 21,
69};
70
71using AppletFooterUiVariant = u8;
72
73// This is "nn::hid::system::AppletDetailedUiType".
74struct AppletDetailedUiType {
75 AppletFooterUiVariant ui_variant;
76 INSERT_PADDING_BYTES(0x2);
77 AppletFooterUiType footer;
78};
79static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
80// This is nn::hid::NpadCommunicationMode
81enum class NpadCommunicationMode : u64 {
82 Mode_5ms = 0,
83 Mode_10ms = 1,
84 Mode_15ms = 2,
85 Default = 3,
86};
87
88enum class NpadRevision : u32 {
89 Revision0 = 0,
90 Revision1 = 1,
91 Revision2 = 2,
92 Revision3 = 3,
93};
94
95// This is nn::hid::detail::ColorAttribute
96enum class ColorAttribute : u32 {
97 Ok = 0,
98 ReadError = 1,
99 NoController = 2,
100};
101static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
102
103// This is nn::hid::detail::NpadFullKeyColorState
104struct NpadFullKeyColorState {
105 ColorAttribute attribute{ColorAttribute::NoController};
106 Core::HID::NpadControllerColor fullkey{};
107};
108static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
109
110// This is nn::hid::detail::NpadJoyColorState
111struct NpadJoyColorState {
112 ColorAttribute attribute{ColorAttribute::NoController};
113 Core::HID::NpadControllerColor left{};
114 Core::HID::NpadControllerColor right{};
115};
116static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
117
118// This is nn::hid::NpadAttribute
119struct NpadAttribute {
120 union {
121 u32 raw{};
122 BitField<0, 1, u32> is_connected;
123 BitField<1, 1, u32> is_wired;
124 BitField<2, 1, u32> is_left_connected;
125 BitField<3, 1, u32> is_left_wired;
126 BitField<4, 1, u32> is_right_connected;
127 BitField<5, 1, u32> is_right_wired;
128 };
129};
130static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
131
132// This is nn::hid::NpadFullKeyState
133// This is nn::hid::NpadHandheldState
134// This is nn::hid::NpadJoyDualState
135// This is nn::hid::NpadJoyLeftState
136// This is nn::hid::NpadJoyRightState
137// This is nn::hid::NpadPalmaState
138// This is nn::hid::NpadSystemExtState
139struct NPadGenericState {
140 s64_le sampling_number{};
141 Core::HID::NpadButtonState npad_buttons{};
142 Core::HID::AnalogStickState l_stick{};
143 Core::HID::AnalogStickState r_stick{};
144 NpadAttribute connection_status{};
145 INSERT_PADDING_BYTES(4); // Reserved
146};
147static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
148
149// This is nn::hid::server::NpadGcTriggerState
150struct NpadGcTriggerState {
151 s64 sampling_number{};
152 s32 l_analog{};
153 s32 r_analog{};
154};
155static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
156
157// This is nn::hid::NpadSystemProperties
158struct NPadSystemProperties {
159 union {
160 s64 raw{};
161 BitField<0, 1, s64> is_charging_joy_dual;
162 BitField<1, 1, s64> is_charging_joy_left;
163 BitField<2, 1, s64> is_charging_joy_right;
164 BitField<3, 1, s64> is_powered_joy_dual;
165 BitField<4, 1, s64> is_powered_joy_left;
166 BitField<5, 1, s64> is_powered_joy_right;
167 BitField<9, 1, s64> is_system_unsupported_button;
168 BitField<10, 1, s64> is_system_ext_unsupported_button;
169 BitField<11, 1, s64> is_vertical;
170 BitField<12, 1, s64> is_horizontal;
171 BitField<13, 1, s64> use_plus;
172 BitField<14, 1, s64> use_minus;
173 BitField<15, 1, s64> use_directional_buttons;
174 };
175};
176static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
177
178// This is nn::hid::NpadSystemButtonProperties
179struct NpadSystemButtonProperties {
180 union {
181 s32 raw{};
182 BitField<0, 1, s32> is_home_button_protection_enabled;
183 };
184};
185static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
186
187// This is nn::hid::system::DeviceType
188struct DeviceType {
189 union {
190 u32 raw{};
191 BitField<0, 1, s32> fullkey;
192 BitField<1, 1, s32> debug_pad;
193 BitField<2, 1, s32> handheld_left;
194 BitField<3, 1, s32> handheld_right;
195 BitField<4, 1, s32> joycon_left;
196 BitField<5, 1, s32> joycon_right;
197 BitField<6, 1, s32> palma;
198 BitField<7, 1, s32> lark_hvc_left;
199 BitField<8, 1, s32> lark_hvc_right;
200 BitField<9, 1, s32> lark_nes_left;
201 BitField<10, 1, s32> lark_nes_right;
202 BitField<11, 1, s32> handheld_lark_hvc_left;
203 BitField<12, 1, s32> handheld_lark_hvc_right;
204 BitField<13, 1, s32> handheld_lark_nes_left;
205 BitField<14, 1, s32> handheld_lark_nes_right;
206 BitField<15, 1, s32> lucia;
207 BitField<16, 1, s32> lagon;
208 BitField<17, 1, s32> lager;
209 BitField<31, 1, s32> system;
210 };
211};
212
213// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
214struct NfcXcdDeviceHandleStateImpl {
215 u64 handle{};
216 bool is_available{};
217 bool is_activated{};
218 INSERT_PADDING_BYTES(0x6); // Reserved
219 u64 sampling_number{};
220};
221static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
222 "NfcXcdDeviceHandleStateImpl is an invalid size");
223
224// This is nn::hid::NpadLarkType
225enum class NpadLarkType : u32 {
226 Invalid,
227 H1,
228 H2,
229 NL,
230 NR,
231};
232
233// This is nn::hid::NpadLuciaType
234enum class NpadLuciaType : u32 {
235 Invalid,
236 J,
237 E,
238 U,
239};
240
241// This is nn::hid::NpadLagonType
242enum class NpadLagonType : u32 {
243 Invalid,
244};
245
246// This is nn::hid::NpadLagerType
247enum class NpadLagerType : u32 {
248 Invalid,
249 J,
250 E,
251 U,
252};
253
254} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/touch_types.h b/src/core/hle/service/hid/controllers/types/touch_types.h
new file mode 100644
index 000000000..efeaa796d
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/touch_types.h
@@ -0,0 +1,90 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include <array>
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
11#include "common/common_types.h"
12#include "common/point.h"
13#include "core/hid/hid_types.h"
14
15namespace Service::HID {
16static constexpr std::size_t MAX_FINGERS = 16;
17static constexpr size_t MAX_POINTS = 4;
18
19// This is nn::hid::GestureType
20enum class GestureType : u32 {
21 Idle, // Nothing touching the screen
22 Complete, // Set at the end of a touch event
23 Cancel, // Set when the number of fingers change
24 Touch, // A finger just touched the screen
25 Press, // Set if last type is touch and the finger hasn't moved
26 Tap, // Fast press then release
27 Pan, // All points moving together across the screen
28 Swipe, // Fast press movement and release of a single point
29 Pinch, // All points moving away/closer to the midpoint
30 Rotate, // All points rotating from the midpoint
31};
32
33// This is nn::hid::GestureDirection
34enum class GestureDirection : u32 {
35 None,
36 Left,
37 Up,
38 Right,
39 Down,
40};
41
42// This is nn::hid::GestureAttribute
43struct GestureAttribute {
44 union {
45 u32 raw{};
46
47 BitField<4, 1, u32> is_new_touch;
48 BitField<8, 1, u32> is_double_tap;
49 };
50};
51static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
52
53// This is nn::hid::GestureState
54struct GestureState {
55 s64 sampling_number{};
56 s64 detection_count{};
57 GestureType type{GestureType::Idle};
58 GestureDirection direction{GestureDirection::None};
59 Common::Point<s32> pos{};
60 Common::Point<s32> delta{};
61 f32 vel_x{};
62 f32 vel_y{};
63 GestureAttribute attributes{};
64 f32 scale{};
65 f32 rotation_angle{};
66 s32 point_count{};
67 std::array<Common::Point<s32>, 4> points{};
68};
69static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
70
71struct GestureProperties {
72 std::array<Common::Point<s32>, MAX_POINTS> points{};
73 std::size_t active_points{};
74 Common::Point<s32> mid_point{};
75 s64 detection_count{};
76 u64 delta_time{};
77 f32 average_distance{};
78 f32 angle{};
79};
80
81// This is nn::hid::TouchScreenState
82struct TouchScreenState {
83 s64 sampling_number{};
84 s32 entry_count{};
85 INSERT_PADDING_BYTES(4); // Reserved
86 std::array<Core::HID::TouchState, MAX_FINGERS> states{};
87};
88static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
89
90} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
deleted file mode 100644
index 0aaed1fa7..000000000
--- a/src/core/hle/service/hid/controllers/xpad.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cstring>
5#include "common/common_types.h"
6#include "core/core_timing.h"
7#include "core/hid/hid_core.h"
8#include "core/hle/service/hid/controllers/xpad.h"
9
10namespace Service::HID {
11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
12
13XPad::XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
14 static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size,
15 "XpadSharedMemory is bigger than the shared memory");
16 shared_memory = std::construct_at(
17 reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
18}
19XPad::~XPad() = default;
20
21void XPad::OnInit() {}
22
23void XPad::OnRelease() {}
24
25void XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
26 if (!IsControllerActivated()) {
27 shared_memory->basic_xpad_lifo.buffer_count = 0;
28 shared_memory->basic_xpad_lifo.buffer_tail = 0;
29 return;
30 }
31
32 const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state;
33 next_state.sampling_number = last_entry.sampling_number + 1;
34 // TODO(ogniK): Update xpad states
35
36 shared_memory->basic_xpad_lifo.WriteNextEntry(next_state);
37}
38
39} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
deleted file mode 100644
index 9e63a317a..000000000
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ /dev/null
@@ -1,112 +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 "common/bit_field.h"
7#include "common/common_types.h"
8#include "core/hid/hid_types.h"
9#include "core/hle/service/hid/controllers/controller_base.h"
10#include "core/hle/service/hid/ring_lifo.h"
11
12namespace Service::HID {
13class XPad final : public ControllerBase {
14public:
15 explicit XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
16 ~XPad() override;
17
18 // Called when the controller is initialized
19 void OnInit() override;
20
21 // When the controller is released
22 void OnRelease() override;
23
24 // When the controller is requesting an update for the shared memory
25 void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
26
27private:
28 // This is nn::hid::BasicXpadAttributeSet
29 struct BasicXpadAttributeSet {
30 union {
31 u32 raw{};
32 BitField<0, 1, u32> is_connected;
33 BitField<1, 1, u32> is_wired;
34 BitField<2, 1, u32> is_left_connected;
35 BitField<3, 1, u32> is_left_wired;
36 BitField<4, 1, u32> is_right_connected;
37 BitField<5, 1, u32> is_right_wired;
38 };
39 };
40 static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
41
42 // This is nn::hid::BasicXpadButtonSet
43 struct BasicXpadButtonSet {
44 union {
45 u32 raw{};
46 // Button states
47 BitField<0, 1, u32> a;
48 BitField<1, 1, u32> b;
49 BitField<2, 1, u32> x;
50 BitField<3, 1, u32> y;
51 BitField<4, 1, u32> l_stick;
52 BitField<5, 1, u32> r_stick;
53 BitField<6, 1, u32> l;
54 BitField<7, 1, u32> r;
55 BitField<8, 1, u32> zl;
56 BitField<9, 1, u32> zr;
57 BitField<10, 1, u32> plus;
58 BitField<11, 1, u32> minus;
59
60 // D-Pad
61 BitField<12, 1, u32> d_left;
62 BitField<13, 1, u32> d_up;
63 BitField<14, 1, u32> d_right;
64 BitField<15, 1, u32> d_down;
65
66 // Left JoyStick
67 BitField<16, 1, u32> l_stick_left;
68 BitField<17, 1, u32> l_stick_up;
69 BitField<18, 1, u32> l_stick_right;
70 BitField<19, 1, u32> l_stick_down;
71
72 // Right JoyStick
73 BitField<20, 1, u32> r_stick_left;
74 BitField<21, 1, u32> r_stick_up;
75 BitField<22, 1, u32> r_stick_right;
76 BitField<23, 1, u32> r_stick_down;
77
78 // Not always active?
79 BitField<24, 1, u32> left_sl;
80 BitField<25, 1, u32> left_sr;
81
82 BitField<26, 1, u32> right_sl;
83 BitField<27, 1, u32> right_sr;
84
85 BitField<28, 1, u32> palma;
86 BitField<30, 1, u32> handheld_left_b;
87 };
88 };
89 static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
90
91 // This is nn::hid::detail::BasicXpadState
92 struct BasicXpadState {
93 s64 sampling_number{};
94 BasicXpadAttributeSet attributes{};
95 BasicXpadButtonSet pad_states{};
96 Core::HID::AnalogStickState l_stick{};
97 Core::HID::AnalogStickState r_stick{};
98 };
99 static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
100
101 struct XpadSharedMemory {
102 // This is nn::hid::detail::BasicXpadLifo
103 Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{};
104 static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
105 INSERT_PADDING_WORDS(0x4E);
106 };
107 static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size");
108
109 BasicXpadState next_state{};
110 XpadSharedMemory* shared_memory = nullptr;
111};
112} // namespace Service::HID
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index 9585bdaf0..6dc976fe1 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -19,6 +19,14 @@ constexpr Result NpadIsSameType{ErrorModule::HID, 602};
19constexpr Result InvalidNpadId{ErrorModule::HID, 709}; 19constexpr Result InvalidNpadId{ErrorModule::HID, 709};
20constexpr Result NpadNotConnected{ErrorModule::HID, 710}; 20constexpr Result NpadNotConnected{ErrorModule::HID, 710};
21constexpr Result InvalidArraySize{ErrorModule::HID, 715}; 21constexpr Result InvalidArraySize{ErrorModule::HID, 715};
22
23constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041};
24constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042};
25constexpr Result ResultSharedMemoryNotInitialized{ErrorModule::HID, 1043};
26constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044};
27constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046};
28constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047};
29
22constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; 30constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302};
23 31
24} // namespace Service::HID 32} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1b7381d8d..afbcb019f 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1,6 +1,8 @@
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 "core/hle/kernel/k_process.h"
5#include "core/hle/kernel/kernel.h"
4#include "core/hle/service/hid/hid.h" 6#include "core/hle/service/hid/hid.h"
5#include "core/hle/service/hid/hid_debug_server.h" 7#include "core/hle/service/hid/hid_debug_server.h"
6#include "core/hle/service/hid/hid_firmware_settings.h" 8#include "core/hle/service/hid/hid_firmware_settings.h"
@@ -20,6 +22,12 @@ void LoopProcess(Core::System& system) {
20 std::shared_ptr<HidFirmwareSettings> firmware_settings = 22 std::shared_ptr<HidFirmwareSettings> firmware_settings =
21 std::make_shared<HidFirmwareSettings>(); 23 std::make_shared<HidFirmwareSettings>();
22 24
25 // TODO: Remove this hack until this service is emulated properly.
26 const auto process_list = system.Kernel().GetProcessList();
27 if (!process_list.empty()) {
28 resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
29 }
30
23 server_manager->RegisterNamedService( 31 server_manager->RegisterNamedService(
24 "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); 32 "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings));
25 server_manager->RegisterNamedService( 33 server_manager->RegisterNamedService(
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index a7d1578d9..de24b0401 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -28,6 +28,7 @@
28#include "core/hle/service/hid/controllers/seven_six_axis.h" 28#include "core/hle/service/hid/controllers/seven_six_axis.h"
29#include "core/hle/service/hid/controllers/six_axis.h" 29#include "core/hle/service/hid/controllers/six_axis.h"
30#include "core/hle/service/hid/controllers/touchscreen.h" 30#include "core/hle/service/hid/controllers/touchscreen.h"
31#include "core/hle/service/hid/controllers/types/npad_types.h"
31 32
32namespace Service::HID { 33namespace Service::HID {
33 34
@@ -222,11 +223,14 @@ void IHidServer::CreateAppletResource(HLERequestContext& ctx) {
222 IPC::RequestParser rp{ctx}; 223 IPC::RequestParser rp{ctx};
223 const auto applet_resource_user_id{rp.Pop<u64>()}; 224 const auto applet_resource_user_id{rp.Pop<u64>()};
224 225
225 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 226 Result result = GetResourceManager()->CreateAppletResource(applet_resource_user_id);
227
228 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}",
229 applet_resource_user_id, result.raw);
226 230
227 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 231 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
228 rb.Push(ResultSuccess); 232 rb.Push(result);
229 rb.PushIpcInterface<IAppletResource>(system, resource_manager); 233 rb.PushIpcInterface<IAppletResource>(system, resource_manager, applet_resource_user_id);
230} 234}
231 235
232void IHidServer::ActivateDebugPad(HLERequestContext& ctx) { 236void IHidServer::ActivateDebugPad(HLERequestContext& ctx) {
@@ -1096,7 +1100,7 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
1096void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { 1100void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
1097 IPC::RequestParser rp{ctx}; 1101 IPC::RequestParser rp{ctx};
1098 struct Parameters { 1102 struct Parameters {
1099 NPad::NpadRevision revision; 1103 NpadRevision revision;
1100 INSERT_PADDING_WORDS_NOINIT(1); 1104 INSERT_PADDING_WORDS_NOINIT(1);
1101 u64 applet_resource_user_id; 1105 u64 applet_resource_user_id;
1102 }; 1106 };
@@ -1119,7 +1123,7 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
1119void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) { 1123void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) {
1120 IPC::RequestParser rp{ctx}; 1124 IPC::RequestParser rp{ctx};
1121 const auto applet_resource_user_id{rp.Pop<u64>()}; 1125 const auto applet_resource_user_id{rp.Pop<u64>()};
1122 const auto hold_type{rp.PopEnum<NPad::NpadJoyHoldType>()}; 1126 const auto hold_type{rp.PopEnum<NpadJoyHoldType>()};
1123 1127
1124 GetResourceManager()->GetNpad()->SetHoldType(hold_type); 1128 GetResourceManager()->GetNpad()->SetHoldType(hold_type);
1125 1129
@@ -1154,8 +1158,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx)
1154 1158
1155 Core::HID::NpadIdType new_npad_id{}; 1159 Core::HID::NpadIdType new_npad_id{};
1156 auto controller = GetResourceManager()->GetNpad(); 1160 auto controller = GetResourceManager()->GetNpad();
1157 controller->SetNpadMode(new_npad_id, parameters.npad_id, NPad::NpadJoyDeviceType::Left, 1161 controller->SetNpadMode(new_npad_id, parameters.npad_id, NpadJoyDeviceType::Left,
1158 NPad::NpadJoyAssignmentMode::Single); 1162 NpadJoyAssignmentMode::Single);
1159 1163
1160 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, 1164 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1161 parameters.applet_resource_user_id); 1165 parameters.applet_resource_user_id);
@@ -1170,7 +1174,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
1170 Core::HID::NpadIdType npad_id; 1174 Core::HID::NpadIdType npad_id;
1171 INSERT_PADDING_WORDS_NOINIT(1); 1175 INSERT_PADDING_WORDS_NOINIT(1);
1172 u64 applet_resource_user_id; 1176 u64 applet_resource_user_id;
1173 NPad::NpadJoyDeviceType npad_joy_device_type; 1177 NpadJoyDeviceType npad_joy_device_type;
1174 }; 1178 };
1175 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); 1179 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1176 1180
@@ -1179,7 +1183,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
1179 Core::HID::NpadIdType new_npad_id{}; 1183 Core::HID::NpadIdType new_npad_id{};
1180 auto controller = GetResourceManager()->GetNpad(); 1184 auto controller = GetResourceManager()->GetNpad();
1181 controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, 1185 controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
1182 NPad::NpadJoyAssignmentMode::Single); 1186 NpadJoyAssignmentMode::Single);
1183 1187
1184 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", 1188 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1185 parameters.npad_id, parameters.applet_resource_user_id, 1189 parameters.npad_id, parameters.applet_resource_user_id,
@@ -1202,7 +1206,7 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
1202 1206
1203 Core::HID::NpadIdType new_npad_id{}; 1207 Core::HID::NpadIdType new_npad_id{};
1204 auto controller = GetResourceManager()->GetNpad(); 1208 auto controller = GetResourceManager()->GetNpad();
1205 controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NPad::NpadJoyAssignmentMode::Dual); 1209 controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NpadJoyAssignmentMode::Dual);
1206 1210
1207 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, 1211 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
1208 parameters.applet_resource_user_id); // Spams a lot when controller applet is open 1212 parameters.applet_resource_user_id); // Spams a lot when controller applet is open
@@ -1254,7 +1258,7 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) {
1254void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) { 1258void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
1255 IPC::RequestParser rp{ctx}; 1259 IPC::RequestParser rp{ctx};
1256 const auto applet_resource_user_id{rp.Pop<u64>()}; 1260 const auto applet_resource_user_id{rp.Pop<u64>()};
1257 const auto activation_mode{rp.PopEnum<NPad::NpadHandheldActivationMode>()}; 1261 const auto activation_mode{rp.PopEnum<NpadHandheldActivationMode>()};
1258 1262
1259 GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode); 1263 GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode);
1260 1264
@@ -1346,7 +1350,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
1346 Core::HID::NpadIdType npad_id; 1350 Core::HID::NpadIdType npad_id;
1347 INSERT_PADDING_WORDS_NOINIT(1); 1351 INSERT_PADDING_WORDS_NOINIT(1);
1348 u64 applet_resource_user_id; 1352 u64 applet_resource_user_id;
1349 NPad::NpadJoyDeviceType npad_joy_device_type; 1353 NpadJoyDeviceType npad_joy_device_type;
1350 }; 1354 };
1351 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); 1355 static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
1352 1356
@@ -1356,7 +1360,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
1356 auto controller = GetResourceManager()->GetNpad(); 1360 auto controller = GetResourceManager()->GetNpad();
1357 const auto is_reassigned = 1361 const auto is_reassigned =
1358 controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, 1362 controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
1359 NPad::NpadJoyAssignmentMode::Single); 1363 NpadJoyAssignmentMode::Single);
1360 1364
1361 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", 1365 LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
1362 parameters.npad_id, parameters.applet_resource_user_id, 1366 parameters.npad_id, parameters.applet_resource_user_id,
@@ -2312,7 +2316,7 @@ void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
2312void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { 2316void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) {
2313 IPC::RequestParser rp{ctx}; 2317 IPC::RequestParser rp{ctx};
2314 const auto applet_resource_user_id{rp.Pop<u64>()}; 2318 const auto applet_resource_user_id{rp.Pop<u64>()};
2315 const auto communication_mode{rp.PopEnum<NPad::NpadCommunicationMode>()}; 2319 const auto communication_mode{rp.PopEnum<NpadCommunicationMode>()};
2316 2320
2317 GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode); 2321 GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode);
2318 2322
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index b56d0347a..5cc88c4a1 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -3,7 +3,9 @@
3 3
4#include "core/hid/hid_core.h" 4#include "core/hid/hid_core.h"
5#include "core/hle/service/hid/controllers/npad.h" 5#include "core/hle/service/hid/controllers/npad.h"
6#include "core/hle/service/hid/controllers/palma.h"
6#include "core/hle/service/hid/controllers/touchscreen.h" 7#include "core/hle/service/hid/controllers/touchscreen.h"
8#include "core/hle/service/hid/controllers/types/npad_types.h"
7#include "core/hle/service/hid/errors.h" 9#include "core/hle/service/hid/errors.h"
8#include "core/hle/service/hid/hid_system_server.h" 10#include "core/hle/service/hid/hid_system_server.h"
9#include "core/hle/service/hid/resource_manager.h" 11#include "core/hle/service/hid/resource_manager.h"
@@ -63,13 +65,13 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
63 {329, nullptr, "DetachAbstractedPadAll"}, 65 {329, nullptr, "DetachAbstractedPadAll"},
64 {330, nullptr, "CheckAbstractedPadConnection"}, 66 {330, nullptr, "CheckAbstractedPadConnection"},
65 {500, nullptr, "SetAppletResourceUserId"}, 67 {500, nullptr, "SetAppletResourceUserId"},
66 {501, nullptr, "RegisterAppletResourceUserId"}, 68 {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"},
67 {502, nullptr, "UnregisterAppletResourceUserId"}, 69 {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"},
68 {503, nullptr, "EnableAppletToGetInput"}, 70 {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"},
69 {504, nullptr, "SetAruidValidForVibration"}, 71 {504, nullptr, "SetAruidValidForVibration"},
70 {505, nullptr, "EnableAppletToGetSixAxisSensor"}, 72 {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"},
71 {506, nullptr, "EnableAppletToGetPadInput"}, 73 {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"},
72 {507, nullptr, "EnableAppletToGetTouchScreen"}, 74 {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"},
73 {510, nullptr, "SetVibrationMasterVolume"}, 75 {510, nullptr, "SetVibrationMasterVolume"},
74 {511, nullptr, "GetVibrationMasterVolume"}, 76 {511, nullptr, "GetVibrationMasterVolume"},
75 {512, nullptr, "BeginPermitVibrationSession"}, 77 {512, nullptr, "BeginPermitVibrationSession"},
@@ -327,7 +329,7 @@ void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
327 LOG_DEBUG(Service_HID, "called, npad_id_type={}", 329 LOG_DEBUG(Service_HID, "called, npad_id_type={}",
328 npad_id_type); // Spams a lot when controller applet is running 330 npad_id_type); // Spams a lot when controller applet is running
329 331
330 const NPad::AppletDetailedUiType detailed_ui_type = 332 const AppletDetailedUiType detailed_ui_type =
331 GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type); 333 GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type);
332 334
333 IPC::ResponseBuilder rb{ctx, 3}; 335 IPC::ResponseBuilder rb{ctx, 3};
@@ -420,6 +422,129 @@ void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) {
420 IPC::ResponseBuilder rb{ctx, 2}; 422 IPC::ResponseBuilder rb{ctx, 2};
421 rb.Push(ResultSuccess); 423 rb.Push(ResultSuccess);
422} 424}
425void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) {
426 IPC::RequestParser rp{ctx};
427 struct Parameters {
428 bool enable_input;
429 INSERT_PADDING_WORDS_NOINIT(1);
430 u64 applet_resource_user_id;
431 };
432 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
433
434 const auto parameters{rp.PopRaw<Parameters>()};
435
436 LOG_INFO(Service_HID, "called, enable_input={}, applet_resource_user_id={}",
437 parameters.enable_input, parameters.applet_resource_user_id);
438
439 Result result = GetResourceManager()->RegisterAppletResourceUserId(
440 parameters.applet_resource_user_id, parameters.enable_input);
441
442 if (result.IsSuccess()) {
443 // result = GetResourceManager()->GetNpad()->RegisterAppletResourceUserId(
444 // parameters.applet_resource_user_id);
445 }
446
447 IPC::ResponseBuilder rb{ctx, 2};
448 rb.Push(ResultSuccess);
449}
450
451void IHidSystemServer::UnregisterAppletResourceUserId(HLERequestContext& ctx) {
452 IPC::RequestParser rp{ctx};
453 u64 applet_resource_user_id{rp.Pop<u64>()};
454
455 LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
456
457 GetResourceManager()->UnregisterAppletResourceUserId(applet_resource_user_id);
458 // GetResourceManager()->GetNpad()->UnregisterAppletResourceUserId(applet_resource_user_id);
459 // GetResourceManager()->GetPalma()->UnregisterAppletResourceUserId(applet_resource_user_id);
460
461 IPC::ResponseBuilder rb{ctx, 2};
462 rb.Push(ResultSuccess);
463}
464
465void IHidSystemServer::EnableAppletToGetInput(HLERequestContext& ctx) {
466 IPC::RequestParser rp{ctx};
467 struct Parameters {
468 bool is_enabled;
469 INSERT_PADDING_WORDS_NOINIT(1);
470 u64 applet_resource_user_id;
471 };
472 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
473
474 const auto parameters{rp.PopRaw<Parameters>()};
475
476 LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
477 parameters.is_enabled, parameters.applet_resource_user_id);
478
479 GetResourceManager()->EnableInput(parameters.applet_resource_user_id, parameters.is_enabled);
480 // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id);
481
482 IPC::ResponseBuilder rb{ctx, 2};
483 rb.Push(ResultSuccess);
484}
485
486void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) {
487 IPC::RequestParser rp{ctx};
488 struct Parameters {
489 bool is_enabled;
490 INSERT_PADDING_WORDS_NOINIT(1);
491 u64 applet_resource_user_id;
492 };
493 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
494
495 const auto parameters{rp.PopRaw<Parameters>()};
496
497 LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
498 parameters.is_enabled, parameters.applet_resource_user_id);
499
500 GetResourceManager()->EnableTouchScreen(parameters.applet_resource_user_id,
501 parameters.is_enabled);
502
503 IPC::ResponseBuilder rb{ctx, 2};
504 rb.Push(ResultSuccess);
505}
506
507void IHidSystemServer::EnableAppletToGetPadInput(HLERequestContext& ctx) {
508 IPC::RequestParser rp{ctx};
509 struct Parameters {
510 bool is_enabled;
511 INSERT_PADDING_WORDS_NOINIT(1);
512 u64 applet_resource_user_id;
513 };
514 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
515
516 const auto parameters{rp.PopRaw<Parameters>()};
517
518 LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
519 parameters.is_enabled, parameters.applet_resource_user_id);
520
521 GetResourceManager()->EnablePadInput(parameters.applet_resource_user_id, parameters.is_enabled);
522 // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id);
523
524 IPC::ResponseBuilder rb{ctx, 2};
525 rb.Push(ResultSuccess);
526}
527
528void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) {
529 IPC::RequestParser rp{ctx};
530 struct Parameters {
531 bool is_enabled;
532 INSERT_PADDING_WORDS_NOINIT(1);
533 u64 applet_resource_user_id;
534 };
535 static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
536
537 const auto parameters{rp.PopRaw<Parameters>()};
538
539 LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
540 parameters.is_enabled, parameters.applet_resource_user_id);
541
542 GetResourceManager()->EnableTouchScreen(parameters.applet_resource_user_id,
543 parameters.is_enabled);
544
545 IPC::ResponseBuilder rb{ctx, 2};
546 rb.Push(ResultSuccess);
547}
423 548
424void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) { 549void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) {
425 LOG_INFO(Service_AM, "(STUBBED) called"); 550 LOG_INFO(Service_AM, "(STUBBED) called");
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h
index 822d5e5b9..1e623dfc2 100644
--- a/src/core/hle/service/hid/hid_system_server.h
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -38,6 +38,12 @@ private:
38 void HasLeftRightBattery(HLERequestContext& ctx); 38 void HasLeftRightBattery(HLERequestContext& ctx);
39 void GetUniquePadsFromNpad(HLERequestContext& ctx); 39 void GetUniquePadsFromNpad(HLERequestContext& ctx);
40 void GetIrSensorState(HLERequestContext& ctx); 40 void GetIrSensorState(HLERequestContext& ctx);
41 void RegisterAppletResourceUserId(HLERequestContext& ctx);
42 void UnregisterAppletResourceUserId(HLERequestContext& ctx);
43 void EnableAppletToGetInput(HLERequestContext& ctx);
44 void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx);
45 void EnableAppletToGetPadInput(HLERequestContext& ctx);
46 void EnableAppletToGetTouchScreen(HLERequestContext& ctx);
41 void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); 47 void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
42 void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); 48 void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
43 void GetRegisteredDevices(HLERequestContext& ctx); 49 void GetRegisteredDevices(HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp
index e76d4eea9..6c6cbd802 100644
--- a/src/core/hle/service/hid/resource_manager.cpp
+++ b/src/core/hle/service/hid/resource_manager.cpp
@@ -9,6 +9,7 @@
9#include "core/hle/service/hid/resource_manager.h" 9#include "core/hle/service/hid/resource_manager.h"
10#include "core/hle/service/ipc_helpers.h" 10#include "core/hle/service/ipc_helpers.h"
11 11
12#include "core/hle/service/hid/controllers/applet_resource.h"
12#include "core/hle/service/hid/controllers/console_six_axis.h" 13#include "core/hle/service/hid/controllers/console_six_axis.h"
13#include "core/hle/service/hid/controllers/debug_pad.h" 14#include "core/hle/service/hid/controllers/debug_pad.h"
14#include "core/hle/service/hid/controllers/gesture.h" 15#include "core/hle/service/hid/controllers/gesture.h"
@@ -17,10 +18,10 @@
17#include "core/hle/service/hid/controllers/npad.h" 18#include "core/hle/service/hid/controllers/npad.h"
18#include "core/hle/service/hid/controllers/palma.h" 19#include "core/hle/service/hid/controllers/palma.h"
19#include "core/hle/service/hid/controllers/seven_six_axis.h" 20#include "core/hle/service/hid/controllers/seven_six_axis.h"
21#include "core/hle/service/hid/controllers/shared_memory_format.h"
20#include "core/hle/service/hid/controllers/six_axis.h" 22#include "core/hle/service/hid/controllers/six_axis.h"
21#include "core/hle/service/hid/controllers/stubbed.h" 23#include "core/hle/service/hid/controllers/stubbed.h"
22#include "core/hle/service/hid/controllers/touchscreen.h" 24#include "core/hle/service/hid/controllers/touchscreen.h"
23#include "core/hle/service/hid/controllers/xpad.h"
24 25
25namespace Service::HID { 26namespace Service::HID {
26 27
@@ -33,7 +34,9 @@ constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 10
33constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) 34constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
34 35
35ResourceManager::ResourceManager(Core::System& system_) 36ResourceManager::ResourceManager(Core::System& system_)
36 : system{system_}, service_context{system_, "hid"} {} 37 : system{system_}, service_context{system_, "hid"} {
38 applet_resource = std::make_shared<AppletResource>(system);
39}
37 40
38ResourceManager::~ResourceManager() = default; 41ResourceManager::~ResourceManager() = default;
39 42
@@ -42,41 +45,49 @@ void ResourceManager::Initialize() {
42 return; 45 return;
43 } 46 }
44 47
45 u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer(); 48 system.HIDCore().ReloadInputDevices();
46 debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory); 49 is_initialized = true;
47 mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory); 50}
48 debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory); 51
49 keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory); 52void ResourceManager::InitializeController(u64 aruid) {
50 unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory); 53 SharedMemoryFormat* shared_memory = nullptr;
51 npad = std::make_shared<NPad>(system.HIDCore(), shared_memory, service_context); 54 const auto result = applet_resource->GetSharedMemoryFormat(&shared_memory, aruid);
52 gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory); 55 if (result.IsError()) {
53 touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory); 56 return;
54 xpad = std::make_shared<XPad>(system.HIDCore(), shared_memory); 57 }
58
59 debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory->debug_pad);
60 mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory->mouse);
61 debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory->debug_mouse);
62 keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory->keyboard);
63 unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory->unique_pad.header);
64 npad = std::make_shared<NPad>(system.HIDCore(), shared_memory->npad, service_context);
65 gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory->gesture);
66 touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory->touch_screen);
55 67
56 palma = std::make_shared<Palma>(system.HIDCore(), shared_memory, service_context); 68 palma = std::make_shared<Palma>(system.HIDCore(), service_context);
57 69
58 home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory); 70 home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory->home_button.header);
59 sleep_button = std::make_shared<SleepButton>(system.HIDCore(), shared_memory); 71 sleep_button =
60 capture_button = std::make_shared<CaptureButton>(system.HIDCore(), shared_memory); 72 std::make_shared<SleepButton>(system.HIDCore(), shared_memory->sleep_button.header);
73 capture_button =
74 std::make_shared<CaptureButton>(system.HIDCore(), shared_memory->capture_button.header);
75 digitizer = std::make_shared<Digitizer>(system.HIDCore(), shared_memory->digitizer.header);
61 76
62 six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad); 77 six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
63 console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory); 78 console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory->console);
64 seven_six_axis = std::make_shared<SevenSixAxis>(system); 79 seven_six_axis = std::make_shared<SevenSixAxis>(system);
65 80
66 home_button->SetCommonHeaderOffset(0x4C00);
67 sleep_button->SetCommonHeaderOffset(0x4E00);
68 capture_button->SetCommonHeaderOffset(0x5000);
69 unique_pad->SetCommonHeaderOffset(0x5A00);
70 debug_mouse->SetCommonHeaderOffset(0x3DC00);
71
72 // Homebrew doesn't try to activate some controllers, so we activate them by default 81 // Homebrew doesn't try to activate some controllers, so we activate them by default
73 npad->Activate(); 82 npad->Activate();
74 six_axis->Activate(); 83 six_axis->Activate();
75 touch_screen->Activate(); 84 touch_screen->Activate();
85}
76 86
77 system.HIDCore().ReloadInputDevices(); 87std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const {
78 is_initialized = true; 88 return applet_resource;
79} 89}
90
80std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const { 91std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const {
81 return capture_button; 92 return capture_button;
82} 93}
@@ -93,6 +104,10 @@ std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const {
93 return debug_pad; 104 return debug_pad;
94} 105}
95 106
107std::shared_ptr<Digitizer> ResourceManager::GetDigitizer() const {
108 return digitizer;
109}
110
96std::shared_ptr<Gesture> ResourceManager::GetGesture() const { 111std::shared_ptr<Gesture> ResourceManager::GetGesture() const {
97 return gesture; 112 return gesture;
98} 113}
@@ -137,10 +152,86 @@ std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const {
137 return unique_pad; 152 return unique_pad;
138} 153}
139 154
155Result ResourceManager::CreateAppletResource(u64 aruid) {
156 if (aruid == 0) {
157 const auto result = RegisterCoreAppletResource();
158 if (result.IsError()) {
159 return result;
160 }
161 return GetNpad()->Activate();
162 }
163
164 const auto result = CreateAppletResourceImpl(aruid);
165 if (result.IsError()) {
166 return result;
167 }
168 return GetNpad()->Activate(aruid);
169}
170
171Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
172 std::scoped_lock lock{shared_mutex};
173 const auto result = applet_resource->CreateAppletResource(aruid);
174 if (result.IsSuccess()) {
175 InitializeController(aruid);
176 }
177 return result;
178}
179
180Result ResourceManager::RegisterCoreAppletResource() {
181 std::scoped_lock lock{shared_mutex};
182 return applet_resource->RegisterCoreAppletResource();
183}
184
185Result ResourceManager::UnregisterCoreAppletResource() {
186 std::scoped_lock lock{shared_mutex};
187 return applet_resource->UnregisterCoreAppletResource();
188}
189
190Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) {
191 std::scoped_lock lock{shared_mutex};
192 return applet_resource->RegisterAppletResourceUserId(aruid, bool_value);
193}
194
195void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) {
196 std::scoped_lock lock{shared_mutex};
197 applet_resource->UnregisterAppletResourceUserId(aruid);
198}
199
200Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
201 std::scoped_lock lock{shared_mutex};
202 return applet_resource->GetSharedMemoryHandle(out_handle, aruid);
203}
204
205void ResourceManager::FreeAppletResourceId(u64 aruid) {
206 std::scoped_lock lock{shared_mutex};
207 applet_resource->FreeAppletResourceId(aruid);
208}
209
210void ResourceManager::EnableInput(u64 aruid, bool is_enabled) {
211 std::scoped_lock lock{shared_mutex};
212 applet_resource->EnableInput(aruid, is_enabled);
213}
214
215void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
216 std::scoped_lock lock{shared_mutex};
217 applet_resource->EnableSixAxisSensor(aruid, is_enabled);
218}
219
220void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) {
221 std::scoped_lock lock{shared_mutex};
222 applet_resource->EnablePadInput(aruid, is_enabled);
223}
224
225void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) {
226 std::scoped_lock lock{shared_mutex};
227 applet_resource->EnableTouchScreen(aruid, is_enabled);
228}
229
140void ResourceManager::UpdateControllers(std::uintptr_t user_data, 230void ResourceManager::UpdateControllers(std::uintptr_t user_data,
141 std::chrono::nanoseconds ns_late) { 231 std::chrono::nanoseconds ns_late) {
142 auto& core_timing = system.CoreTiming(); 232 auto& core_timing = system.CoreTiming();
143 debug_pad->OnUpdate(core_timing); 233 debug_pad->OnUpdate(core_timing);
234 digitizer->OnUpdate(core_timing);
144 unique_pad->OnUpdate(core_timing); 235 unique_pad->OnUpdate(core_timing);
145 gesture->OnUpdate(core_timing); 236 gesture->OnUpdate(core_timing);
146 touch_screen->OnUpdate(core_timing); 237 touch_screen->OnUpdate(core_timing);
@@ -148,7 +239,6 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data,
148 home_button->OnUpdate(core_timing); 239 home_button->OnUpdate(core_timing);
149 sleep_button->OnUpdate(core_timing); 240 sleep_button->OnUpdate(core_timing);
150 capture_button->OnUpdate(core_timing); 241 capture_button->OnUpdate(core_timing);
151 xpad->OnUpdate(core_timing);
152} 242}
153 243
154void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { 244void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
@@ -171,15 +261,15 @@ void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose
171 console_six_axis->OnUpdate(core_timing); 261 console_six_axis->OnUpdate(core_timing);
172} 262}
173 263
174IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource) 264IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
175 : ServiceFramework{system_, "IAppletResource"} { 265 u64 applet_resource_user_id)
266 : ServiceFramework{system_, "IAppletResource"}, aruid{applet_resource_user_id},
267 resource_manager{resource} {
176 static const FunctionInfo functions[] = { 268 static const FunctionInfo functions[] = {
177 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, 269 {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
178 }; 270 };
179 RegisterHandlers(functions); 271 RegisterHandlers(functions);
180 272
181 resource->Initialize();
182
183 // Register update callbacks 273 // Register update callbacks
184 npad_update_event = Core::Timing::CreateEvent( 274 npad_update_event = Core::Timing::CreateEvent(
185 "HID::UpdatePadCallback", 275 "HID::UpdatePadCallback",
@@ -228,14 +318,18 @@ IAppletResource::~IAppletResource() {
228 system.CoreTiming().UnscheduleEvent(default_update_event, 0); 318 system.CoreTiming().UnscheduleEvent(default_update_event, 0);
229 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); 319 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
230 system.CoreTiming().UnscheduleEvent(motion_update_event, 0); 320 system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
321 resource_manager->FreeAppletResourceId(aruid);
231} 322}
232 323
233void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) { 324void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
234 LOG_DEBUG(Service_HID, "called"); 325 Kernel::KSharedMemory* handle;
326 const auto result = resource_manager->GetSharedMemoryHandle(&handle, aruid);
327
328 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw);
235 329
236 IPC::ResponseBuilder rb{ctx, 2, 1}; 330 IPC::ResponseBuilder rb{ctx, 2, 1};
237 rb.Push(ResultSuccess); 331 rb.Push(result);
238 rb.PushCopyObjects(&system.Kernel().GetHidSharedMem()); 332 rb.PushCopyObjects(handle);
239} 333}
240 334
241} // namespace Service::HID 335} // namespace Service::HID
diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h
index 2b6a9b5e6..5ad7cb564 100644
--- a/src/core/hle/service/hid/resource_manager.h
+++ b/src/core/hle/service/hid/resource_manager.h
@@ -6,11 +6,20 @@
6#include "core/hle/service/kernel_helpers.h" 6#include "core/hle/service/kernel_helpers.h"
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Core {
10class System;
11}
12
9namespace Core::Timing { 13namespace Core::Timing {
10struct EventType; 14struct EventType;
11} 15}
12 16
17namespace Kernel {
18class KSharedMemory;
19}
20
13namespace Service::HID { 21namespace Service::HID {
22class AppletResource;
14class Controller_Stubbed; 23class Controller_Stubbed;
15class ConsoleSixAxis; 24class ConsoleSixAxis;
16class DebugPad; 25class DebugPad;
@@ -22,10 +31,10 @@ class Palma;
22class SevenSixAxis; 31class SevenSixAxis;
23class SixAxis; 32class SixAxis;
24class TouchScreen; 33class TouchScreen;
25class XPad;
26 34
27using CaptureButton = Controller_Stubbed; 35using CaptureButton = Controller_Stubbed;
28using DebugMouse = Controller_Stubbed; 36using DebugMouse = Mouse;
37using Digitizer = Controller_Stubbed;
29using HomeButton = Controller_Stubbed; 38using HomeButton = Controller_Stubbed;
30using SleepButton = Controller_Stubbed; 39using SleepButton = Controller_Stubbed;
31using UniquePad = Controller_Stubbed; 40using UniquePad = Controller_Stubbed;
@@ -37,11 +46,14 @@ public:
37 ~ResourceManager(); 46 ~ResourceManager();
38 47
39 void Initialize(); 48 void Initialize();
49 void InitializeController(u64 aruid);
40 50
51 std::shared_ptr<AppletResource> GetAppletResource() const;
41 std::shared_ptr<CaptureButton> GetCaptureButton() const; 52 std::shared_ptr<CaptureButton> GetCaptureButton() const;
42 std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const; 53 std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const;
43 std::shared_ptr<DebugMouse> GetDebugMouse() const; 54 std::shared_ptr<DebugMouse> GetDebugMouse() const;
44 std::shared_ptr<DebugPad> GetDebugPad() const; 55 std::shared_ptr<DebugPad> GetDebugPad() const;
56 std::shared_ptr<Digitizer> GetDigitizer() const;
45 std::shared_ptr<Gesture> GetGesture() const; 57 std::shared_ptr<Gesture> GetGesture() const;
46 std::shared_ptr<HomeButton> GetHomeButton() const; 58 std::shared_ptr<HomeButton> GetHomeButton() const;
47 std::shared_ptr<Keyboard> GetKeyboard() const; 59 std::shared_ptr<Keyboard> GetKeyboard() const;
@@ -54,18 +66,39 @@ public:
54 std::shared_ptr<TouchScreen> GetTouchScreen() const; 66 std::shared_ptr<TouchScreen> GetTouchScreen() const;
55 std::shared_ptr<UniquePad> GetUniquePad() const; 67 std::shared_ptr<UniquePad> GetUniquePad() const;
56 68
69 Result CreateAppletResource(u64 aruid);
70
71 Result RegisterCoreAppletResource();
72 Result UnregisterCoreAppletResource();
73 Result RegisterAppletResourceUserId(u64 aruid, bool bool_value);
74 void UnregisterAppletResourceUserId(u64 aruid);
75
76 Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
77 void FreeAppletResourceId(u64 aruid);
78
79 void EnableInput(u64 aruid, bool is_enabled);
80 void EnableSixAxisSensor(u64 aruid, bool is_enabled);
81 void EnablePadInput(u64 aruid, bool is_enabled);
82 void EnableTouchScreen(u64 aruid, bool is_enabled);
83
57 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 84 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
58 void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 85 void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
59 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 86 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
60 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 87 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
61 88
62private: 89private:
90 Result CreateAppletResourceImpl(u64 aruid);
91
63 bool is_initialized{false}; 92 bool is_initialized{false};
64 93
94 mutable std::mutex shared_mutex;
95 std::shared_ptr<AppletResource> applet_resource = nullptr;
96
65 std::shared_ptr<CaptureButton> capture_button = nullptr; 97 std::shared_ptr<CaptureButton> capture_button = nullptr;
66 std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr; 98 std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr;
67 std::shared_ptr<DebugMouse> debug_mouse = nullptr; 99 std::shared_ptr<DebugMouse> debug_mouse = nullptr;
68 std::shared_ptr<DebugPad> debug_pad = nullptr; 100 std::shared_ptr<DebugPad> debug_pad = nullptr;
101 std::shared_ptr<Digitizer> digitizer = nullptr;
69 std::shared_ptr<Gesture> gesture = nullptr; 102 std::shared_ptr<Gesture> gesture = nullptr;
70 std::shared_ptr<HomeButton> home_button = nullptr; 103 std::shared_ptr<HomeButton> home_button = nullptr;
71 std::shared_ptr<Keyboard> keyboard = nullptr; 104 std::shared_ptr<Keyboard> keyboard = nullptr;
@@ -77,7 +110,6 @@ private:
77 std::shared_ptr<SleepButton> sleep_button = nullptr; 110 std::shared_ptr<SleepButton> sleep_button = nullptr;
78 std::shared_ptr<TouchScreen> touch_screen = nullptr; 111 std::shared_ptr<TouchScreen> touch_screen = nullptr;
79 std::shared_ptr<UniquePad> unique_pad = nullptr; 112 std::shared_ptr<UniquePad> unique_pad = nullptr;
80 std::shared_ptr<XPad> xpad = nullptr;
81 113
82 // TODO: Create these resources 114 // TODO: Create these resources
83 // std::shared_ptr<AudioControl> audio_control = nullptr; 115 // std::shared_ptr<AudioControl> audio_control = nullptr;
@@ -96,7 +128,8 @@ private:
96 128
97class IAppletResource final : public ServiceFramework<IAppletResource> { 129class IAppletResource final : public ServiceFramework<IAppletResource> {
98public: 130public:
99 explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource); 131 explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
132 u64 applet_resource_user_id);
100 ~IAppletResource() override; 133 ~IAppletResource() override;
101 134
102private: 135private:
@@ -106,6 +139,9 @@ private:
106 std::shared_ptr<Core::Timing::EventType> default_update_event; 139 std::shared_ptr<Core::Timing::EventType> default_update_event;
107 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; 140 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
108 std::shared_ptr<Core::Timing::EventType> motion_update_event; 141 std::shared_ptr<Core::Timing::EventType> motion_update_event;
142
143 u64 aruid;
144 std::shared_ptr<ResourceManager> resource_manager;
109}; 145};
110 146
111} // namespace Service::HID 147} // namespace Service::HID
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp
index ff374ae39..38955932c 100644
--- a/src/core/hle/service/hle_ipc.cpp
+++ b/src/core/hle/service/hle_ipc.cpp
@@ -146,8 +146,10 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory::
146 146
147HLERequestContext::~HLERequestContext() = default; 147HLERequestContext::~HLERequestContext() = default;
148 148
149void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_table, 149void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf,
150 u32_le* src_cmdbuf, bool incoming) { 150 bool incoming) {
151 client_handle_table = &process.GetHandleTable();
152
151 IPC::RequestParser rp(src_cmdbuf); 153 IPC::RequestParser rp(src_cmdbuf);
152 command_header = rp.PopRaw<IPC::CommandHeader>(); 154 command_header = rp.PopRaw<IPC::CommandHeader>();
153 155
@@ -160,7 +162,8 @@ void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_ta
160 if (command_header->enable_handle_descriptor) { 162 if (command_header->enable_handle_descriptor) {
161 handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); 163 handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
162 if (handle_descriptor_header->send_current_pid) { 164 if (handle_descriptor_header->send_current_pid) {
163 pid = rp.Pop<u64>(); 165 pid = process.GetProcessId();
166 rp.Skip(2, false);
164 } 167 }
165 if (incoming) { 168 if (incoming) {
166 // Populate the object lists with the data in the IPC request. 169 // Populate the object lists with the data in the IPC request.
@@ -267,9 +270,9 @@ void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_ta
267 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. 270 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
268} 271}
269 272
270Result HLERequestContext::PopulateFromIncomingCommandBuffer( 273Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process,
271 const Kernel::KHandleTable& handle_table, u32_le* src_cmdbuf) { 274 u32_le* src_cmdbuf) {
272 ParseCommandBuffer(handle_table, src_cmdbuf, true); 275 ParseCommandBuffer(process, src_cmdbuf, true);
273 276
274 if (command_header->IsCloseCommand()) { 277 if (command_header->IsCloseCommand()) {
275 // Close does not populate the rest of the IPC header 278 // Close does not populate the rest of the IPC header
diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h
index ad5259a5c..18d464c63 100644
--- a/src/core/hle/service/hle_ipc.h
+++ b/src/core/hle/service/hle_ipc.h
@@ -38,6 +38,7 @@ namespace Kernel {
38class KAutoObject; 38class KAutoObject;
39class KernelCore; 39class KernelCore;
40class KHandleTable; 40class KHandleTable;
41class KProcess;
41class KServerSession; 42class KServerSession;
42class KThread; 43class KThread;
43} // namespace Kernel 44} // namespace Kernel
@@ -75,6 +76,7 @@ protected:
75 76
76using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>; 77using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>;
77using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; 78using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
79using SessionRequestHandlerFactory = std::function<SessionRequestHandlerPtr()>;
78 80
79/** 81/**
80 * Manages the underlying HLE requests for a session, and whether (or not) the session should be 82 * Manages the underlying HLE requests for a session, and whether (or not) the session should be
@@ -194,8 +196,7 @@ public:
194 } 196 }
195 197
196 /// Populates this context with data from the requesting process/thread. 198 /// Populates this context with data from the requesting process/thread.
197 Result PopulateFromIncomingCommandBuffer(const Kernel::KHandleTable& handle_table, 199 Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf);
198 u32_le* src_cmdbuf);
199 200
200 /// Writes data from this context back to the requesting process/thread. 201 /// Writes data from this context back to the requesting process/thread.
201 Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread); 202 Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread);
@@ -358,6 +359,10 @@ public:
358 return *thread; 359 return *thread;
359 } 360 }
360 361
362 Kernel::KHandleTable& GetClientHandleTable() {
363 return *client_handle_table;
364 }
365
361 [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { 366 [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const {
362 return manager.lock(); 367 return manager.lock();
363 } 368 }
@@ -373,12 +378,12 @@ public:
373private: 378private:
374 friend class IPC::ResponseBuilder; 379 friend class IPC::ResponseBuilder;
375 380
376 void ParseCommandBuffer(const Kernel::KHandleTable& handle_table, u32_le* src_cmdbuf, 381 void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming);
377 bool incoming);
378 382
379 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 383 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
380 Kernel::KServerSession* server_session{}; 384 Kernel::KServerSession* server_session{};
381 Kernel::KThread* thread; 385 Kernel::KHandleTable* client_handle_table{};
386 Kernel::KThread* thread{};
382 387
383 std::vector<Handle> incoming_move_handles; 388 std::vector<Handle> incoming_move_handles;
384 std::vector<Handle> incoming_copy_handles; 389 std::vector<Handle> incoming_copy_handles;
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index be996870f..65851fc05 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 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/arm/debug.h"
4#include "core/arm/symbols.h" 5#include "core/arm/symbols.h"
5#include "core/core.h" 6#include "core/core.h"
6#include "core/hle/kernel/k_code_memory.h" 7#include "core/hle/kernel/k_code_memory.h"
@@ -98,8 +99,9 @@ public:
98 if (return_value == 0) { 99 if (return_value == 0) {
99 // The callback has written to the output executable code range, 100 // The callback has written to the output executable code range,
100 // requiring an instruction cache invalidation 101 // requiring an instruction cache invalidation
101 system.InvalidateCpuInstructionCacheRange(configuration.user_rx_memory.offset, 102 Core::InvalidateInstructionCacheRange(process.GetPointerUnsafe(),
102 configuration.user_rx_memory.size); 103 configuration.user_rx_memory.offset,
104 configuration.user_rx_memory.size);
103 105
104 // Write back to the IPC output buffer, if provided 106 // Write back to the IPC output buffer, if provided
105 if (ctx.CanWriteBuffer()) { 107 if (ctx.CanWriteBuffer()) {
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 97b6a9385..ba58b3a09 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -1,117 +1,12 @@
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 <memory>
5#include <fmt/format.h>
6#include <mbedtls/sha256.h>
7
8#include "common/alignment.h"
9#include "common/hex_util.h"
10#include "common/scope_exit.h"
11#include "core/core.h"
12#include "core/hle/kernel/k_page_table.h"
13#include "core/hle/kernel/svc_results.h"
14#include "core/hle/kernel/svc_types.h"
15#include "core/hle/service/ipc_helpers.h"
16#include "core/hle/service/ldr/ldr.h" 4#include "core/hle/service/ldr/ldr.h"
17#include "core/hle/service/server_manager.h" 5#include "core/hle/service/server_manager.h"
18#include "core/hle/service/service.h" 6#include "core/hle/service/service.h"
19#include "core/loader/nro.h"
20#include "core/memory.h"
21 7
22namespace Service::LDR { 8namespace Service::LDR {
23 9
24constexpr Result ERROR_INSUFFICIENT_ADDRESS_SPACE{ErrorModule::RO, 2};
25
26[[maybe_unused]] constexpr Result ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
27constexpr Result ERROR_INVALID_NRO{ErrorModule::Loader, 52};
28constexpr Result ERROR_INVALID_NRR{ErrorModule::Loader, 53};
29constexpr Result ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54};
30constexpr Result ERROR_MAXIMUM_NRO{ErrorModule::Loader, 55};
31constexpr Result ERROR_MAXIMUM_NRR{ErrorModule::Loader, 56};
32constexpr Result ERROR_ALREADY_LOADED{ErrorModule::Loader, 57};
33constexpr Result ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81};
34constexpr Result ERROR_INVALID_SIZE{ErrorModule::Loader, 82};
35constexpr Result ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84};
36[[maybe_unused]] constexpr Result ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85};
37constexpr Result ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
38
39constexpr std::size_t MAXIMUM_LOADED_RO{0x40};
40constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200};
41
42constexpr std::size_t TEXT_INDEX{0};
43constexpr std::size_t RO_INDEX{1};
44constexpr std::size_t DATA_INDEX{2};
45
46struct NRRCertification {
47 u64_le application_id_mask;
48 u64_le application_id_pattern;
49 INSERT_PADDING_BYTES(0x10);
50 std::array<u8, 0x100> public_key; // Also known as modulus
51 std::array<u8, 0x100> signature;
52};
53static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid size.");
54
55struct NRRHeader {
56 u32_le magic;
57 u32_le certification_signature_key_generation; // 9.0.0+
58 INSERT_PADDING_WORDS(2);
59 NRRCertification certification;
60 std::array<u8, 0x100> signature;
61 u64_le application_id;
62 u32_le size;
63 u8 nrr_kind; // 7.0.0+
64 INSERT_PADDING_BYTES(3);
65 u32_le hash_offset;
66 u32_le hash_count;
67 INSERT_PADDING_WORDS(2);
68};
69static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size.");
70
71struct SegmentHeader {
72 u32_le memory_offset;
73 u32_le memory_size;
74};
75static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size.");
76
77struct NROHeader {
78 // Switchbrew calls this "Start" (0x10)
79 INSERT_PADDING_WORDS(1);
80 u32_le mod_offset;
81 INSERT_PADDING_WORDS(2);
82
83 // Switchbrew calls this "Header" (0x70)
84 u32_le magic;
85 u32_le version;
86 u32_le nro_size;
87 u32_le flags;
88 // .text, .ro, .data
89 std::array<SegmentHeader, 3> segment_headers;
90 u32_le bss_size;
91 INSERT_PADDING_WORDS(1);
92 std::array<u8, 0x20> build_id;
93 u32_le dso_handle_offset;
94 INSERT_PADDING_WORDS(1);
95 // .apiInfo, .dynstr, .dynsym
96 std::array<SegmentHeader, 3> segment_headers_2;
97};
98static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
99
100using SHA256Hash = std::array<u8, 0x20>;
101
102struct NROInfo {
103 SHA256Hash hash{};
104 VAddr nro_address{};
105 std::size_t nro_size{};
106 VAddr bss_address{};
107 std::size_t bss_size{};
108 std::size_t text_size{};
109 std::size_t ro_size{};
110 std::size_t data_size{};
111 VAddr src_addr{};
112};
113static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size.");
114
115class DebugMonitor final : public ServiceFramework<DebugMonitor> { 10class DebugMonitor final : public ServiceFramework<DebugMonitor> {
116public: 11public:
117 explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} { 12 explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} {
@@ -158,541 +53,12 @@ public:
158 } 53 }
159}; 54};
160 55
161class RelocatableObject final : public ServiceFramework<RelocatableObject> {
162public:
163 explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} {
164 // clang-format off
165 static const FunctionInfo functions[] = {
166 {0, &RelocatableObject::LoadModule, "LoadModule"},
167 {1, &RelocatableObject::UnloadModule, "UnloadModule"},
168 {2, &RelocatableObject::RegisterModuleInfo, "RegisterModuleInfo"},
169 {3, &RelocatableObject::UnregisterModuleInfo, "UnregisterModuleInfo"},
170 {4, &RelocatableObject::Initialize, "Initialize"},
171 {10, nullptr, "RegisterModuleInfo2"},
172 };
173 // clang-format on
174
175 RegisterHandlers(functions);
176 }
177
178 void RegisterModuleInfo(HLERequestContext& ctx) {
179 struct Parameters {
180 u64_le process_id;
181 u64_le nrr_address;
182 u64_le nrr_size;
183 };
184
185 IPC::RequestParser rp{ctx};
186 const auto [process_id, nrr_address, nrr_size] = rp.PopRaw<Parameters>();
187
188 LOG_DEBUG(Service_LDR,
189 "called with process_id={:016X}, nrr_address={:016X}, nrr_size={:016X}",
190 process_id, nrr_address, nrr_size);
191
192 if (!initialized) {
193 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
194 IPC::ResponseBuilder rb{ctx, 2};
195 rb.Push(ERROR_NOT_INITIALIZED);
196 return;
197 }
198
199 if (nrr.size() >= MAXIMUM_LOADED_RO) {
200 LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs "
201 "(0x40)! Failing...");
202 IPC::ResponseBuilder rb{ctx, 2};
203 rb.Push(ERROR_MAXIMUM_NRR);
204 return;
205 }
206
207 // NRR Address does not fall on 0x1000 byte boundary
208 if (!Common::Is4KBAligned(nrr_address)) {
209 LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!",
210 nrr_address);
211 IPC::ResponseBuilder rb{ctx, 2};
212 rb.Push(ERROR_INVALID_ALIGNMENT);
213 return;
214 }
215
216 // NRR Size is zero or causes overflow
217 if (nrr_address + nrr_size <= nrr_address || nrr_size == 0 ||
218 !Common::Is4KBAligned(nrr_size)) {
219 LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})",
220 nrr_address, nrr_size);
221 IPC::ResponseBuilder rb{ctx, 2};
222 rb.Push(ERROR_INVALID_SIZE);
223 return;
224 }
225
226 // Read NRR data from memory
227 std::vector<u8> nrr_data(nrr_size);
228 system.ApplicationMemory().ReadBlock(nrr_address, nrr_data.data(), nrr_size);
229 NRRHeader header;
230 std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
231
232 if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) {
233 LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic);
234 IPC::ResponseBuilder rb{ctx, 2};
235 rb.Push(ERROR_INVALID_NRR);
236 return;
237 }
238
239 if (header.size != nrr_size) {
240 LOG_ERROR(Service_LDR,
241 "NRR header reported size did not match LoadNrr parameter size! "
242 "(header_size={:016X}, loadnrr_size={:016X})",
243 header.size, nrr_size);
244 IPC::ResponseBuilder rb{ctx, 2};
245 rb.Push(ERROR_INVALID_SIZE);
246 return;
247 }
248
249 if (system.GetApplicationProcessProgramID() != header.application_id) {
250 LOG_ERROR(Service_LDR,
251 "Attempting to load NRR with title ID other than current process. (actual "
252 "{:016X})!",
253 header.application_id);
254 IPC::ResponseBuilder rb{ctx, 2};
255 rb.Push(ERROR_INVALID_NRR);
256 return;
257 }
258
259 std::vector<SHA256Hash> hashes;
260
261 // Copy all hashes in the NRR (specified by hash count/hash offset) into vector.
262 for (std::size_t i = header.hash_offset;
263 i < (header.hash_offset + (header.hash_count * sizeof(SHA256Hash))); i += 8) {
264 SHA256Hash hash;
265 std::memcpy(hash.data(), nrr_data.data() + i, sizeof(SHA256Hash));
266 hashes.emplace_back(hash);
267 }
268
269 nrr.insert_or_assign(nrr_address, std::move(hashes));
270
271 IPC::ResponseBuilder rb{ctx, 2};
272 rb.Push(ResultSuccess);
273 }
274
275 void UnregisterModuleInfo(HLERequestContext& ctx) {
276 IPC::RequestParser rp{ctx};
277 const auto pid = rp.Pop<u64>();
278 const auto nrr_address = rp.Pop<VAddr>();
279
280 LOG_DEBUG(Service_LDR, "called with pid={}, nrr_address={:016X}", pid, nrr_address);
281
282 nrr.erase(nrr_address);
283
284 IPC::ResponseBuilder rb{ctx, 2};
285
286 rb.Push(ResultSuccess);
287 }
288
289 bool ValidateRegionForMap(Kernel::KProcessPageTable& page_table, VAddr start,
290 std::size_t size) const {
291 const std::size_t padding_size{page_table.GetNumGuardPages() * Kernel::PageSize};
292
293 Kernel::KMemoryInfo start_info;
294 Kernel::Svc::PageInfo page_info;
295 R_ASSERT(
296 page_table.QueryInfo(std::addressof(start_info), std::addressof(page_info), start - 1));
297
298 if (start_info.GetState() != Kernel::KMemoryState::Free) {
299 return {};
300 }
301
302 if (start_info.GetAddress() > (start - padding_size)) {
303 return {};
304 }
305
306 Kernel::KMemoryInfo end_info;
307 R_ASSERT(page_table.QueryInfo(std::addressof(end_info), std::addressof(page_info),
308 start + size));
309
310 if (end_info.GetState() != Kernel::KMemoryState::Free) {
311 return {};
312 }
313
314 return (start + size + padding_size) <= (end_info.GetAddress() + end_info.GetSize());
315 }
316
317 Result GetAvailableMapRegion(Kernel::KProcessPageTable& page_table, u64 size, VAddr& out_addr) {
318 size = Common::AlignUp(size, Kernel::PageSize);
319 size += page_table.GetNumGuardPages() * Kernel::PageSize * 4;
320
321 const auto is_region_available = [&](VAddr addr) {
322 const auto end_addr = addr + size;
323 while (addr < end_addr) {
324 if (system.ApplicationMemory().IsValidVirtualAddress(addr)) {
325 return false;
326 }
327
328 if (!page_table.Contains(out_addr, size)) {
329 return false;
330 }
331
332 if (page_table.IsInHeapRegion(out_addr, size)) {
333 return false;
334 }
335
336 if (page_table.IsInAliasRegion(out_addr, size)) {
337 return false;
338 }
339
340 addr += Kernel::PageSize;
341 }
342 return true;
343 };
344
345 bool succeeded = false;
346 const auto map_region_end =
347 GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize();
348 while (current_map_addr < map_region_end) {
349 if (is_region_available(current_map_addr)) {
350 succeeded = true;
351 break;
352 }
353 current_map_addr += 0x100000;
354 }
355
356 if (!succeeded) {
357 ASSERT_MSG(false, "Out of address space!");
358 return Kernel::ResultOutOfMemory;
359 }
360
361 out_addr = current_map_addr;
362 current_map_addr += size;
363
364 return ResultSuccess;
365 }
366
367 Result MapProcessCodeMemory(VAddr* out_map_location, Kernel::KProcess* process, VAddr base_addr,
368 u64 size) {
369 auto& page_table{process->GetPageTable()};
370 VAddr addr{};
371
372 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
373 R_TRY(GetAvailableMapRegion(page_table, size, addr));
374
375 const Result result{page_table.MapCodeMemory(addr, base_addr, size)};
376 if (result == Kernel::ResultInvalidCurrentMemory) {
377 continue;
378 }
379
380 R_TRY(result);
381
382 if (ValidateRegionForMap(page_table, addr, size)) {
383 *out_map_location = addr;
384 return ResultSuccess;
385 }
386 }
387
388 return ERROR_INSUFFICIENT_ADDRESS_SPACE;
389 }
390
391 Result MapNro(VAddr* out_map_location, Kernel::KProcess* process, VAddr nro_addr,
392 std::size_t nro_size, VAddr bss_addr, std::size_t bss_size, std::size_t size) {
393 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
394 auto& page_table{process->GetPageTable()};
395 VAddr addr{};
396
397 R_TRY(MapProcessCodeMemory(&addr, process, nro_addr, nro_size));
398
399 if (bss_size) {
400 auto block_guard = detail::ScopeExit([&] {
401 page_table.UnmapCodeMemory(addr + nro_size, bss_addr, bss_size);
402 page_table.UnmapCodeMemory(addr, nro_addr, nro_size);
403 });
404
405 const Result result{page_table.MapCodeMemory(addr + nro_size, bss_addr, bss_size)};
406
407 if (result == Kernel::ResultInvalidCurrentMemory) {
408 continue;
409 }
410
411 if (result.IsError()) {
412 return result;
413 }
414
415 block_guard.Cancel();
416 }
417
418 if (ValidateRegionForMap(page_table, addr, size)) {
419 *out_map_location = addr;
420 return ResultSuccess;
421 }
422 }
423
424 return ERROR_INSUFFICIENT_ADDRESS_SPACE;
425 }
426
427 Result LoadNro(Kernel::KProcess* process, const NROHeader& nro_header, VAddr nro_addr,
428 VAddr start) const {
429 const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset};
430 const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset};
431 const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset};
432 const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size};
433 const VAddr bss_end_addr{
434 Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)};
435
436 const auto CopyCode = [this](VAddr src_addr, VAddr dst_addr, u64 size) {
437 system.ApplicationMemory().CopyBlock(dst_addr, src_addr, size);
438 };
439 CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start,
440 nro_header.segment_headers[TEXT_INDEX].memory_size);
441 CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start,
442 nro_header.segment_headers[RO_INDEX].memory_size);
443 CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
444 nro_header.segment_headers[DATA_INDEX].memory_size);
445
446 R_TRY(process->GetPageTable().SetProcessMemoryPermission(
447 text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute));
448 R_TRY(process->GetPageTable().SetProcessMemoryPermission(
449 ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));
450
451 return process->GetPageTable().SetProcessMemoryPermission(
452 data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite);
453 }
454
455 void LoadModule(HLERequestContext& ctx) {
456 struct Parameters {
457 u64_le process_id;
458 u64_le image_address;
459 u64_le image_size;
460 u64_le bss_address;
461 u64_le bss_size;
462 };
463
464 IPC::RequestParser rp{ctx};
465 const auto [process_id, nro_address, nro_size, bss_address, bss_size] =
466 rp.PopRaw<Parameters>();
467
468 LOG_DEBUG(Service_LDR,
469 "called with pid={:016X}, nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, "
470 "bss_size={:016X}",
471 process_id, nro_address, nro_size, bss_address, bss_size);
472
473 if (!initialized) {
474 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
475 IPC::ResponseBuilder rb{ctx, 2};
476 rb.Push(ERROR_NOT_INITIALIZED);
477 return;
478 }
479
480 if (nro.size() >= MAXIMUM_LOADED_RO) {
481 LOG_ERROR(Service_LDR, "Loading new NRO would exceed the maximum number of loaded NROs "
482 "(0x40)! Failing...");
483 IPC::ResponseBuilder rb{ctx, 2};
484 rb.Push(ERROR_MAXIMUM_NRO);
485 return;
486 }
487
488 // NRO Address does not fall on 0x1000 byte boundary
489 if (!Common::Is4KBAligned(nro_address)) {
490 LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!",
491 nro_address);
492 IPC::ResponseBuilder rb{ctx, 2};
493 rb.Push(ERROR_INVALID_ALIGNMENT);
494 return;
495 }
496
497 // NRO Size or BSS Size is zero or causes overflow
498 const auto nro_size_valid =
499 nro_size != 0 && nro_address + nro_size > nro_address && Common::Is4KBAligned(nro_size);
500 const auto bss_size_valid = nro_size + bss_size >= nro_size &&
501 (bss_size == 0 || bss_address + bss_size > bss_address);
502
503 if (!nro_size_valid || !bss_size_valid) {
504 LOG_ERROR(Service_LDR,
505 "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, "
506 "bss_address={:016X}, bss_size={:016X})",
507 nro_address, nro_size, bss_address, bss_size);
508 IPC::ResponseBuilder rb{ctx, 2};
509 rb.Push(ERROR_INVALID_SIZE);
510 return;
511 }
512
513 // Read NRO data from memory
514 std::vector<u8> nro_data(nro_size);
515 system.ApplicationMemory().ReadBlock(nro_address, nro_data.data(), nro_size);
516
517 SHA256Hash hash{};
518 mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0);
519
520 // NRO Hash is already loaded
521 if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {
522 return info.second.hash == hash;
523 })) {
524 LOG_ERROR(Service_LDR, "NRO is already loaded!");
525 IPC::ResponseBuilder rb{ctx, 2};
526 rb.Push(ERROR_ALREADY_LOADED);
527 return;
528 }
529
530 // NRO Hash is not in any loaded NRR
531 if (!IsValidNROHash(hash)) {
532 LOG_ERROR(Service_LDR,
533 "NRO hash is not present in any currently loaded NRRs (hash={})!",
534 Common::HexToString(hash));
535 IPC::ResponseBuilder rb{ctx, 2};
536 rb.Push(ERROR_MISSING_NRR_HASH);
537 return;
538 }
539
540 // Load and validate the NRO header
541 NROHeader header{};
542 std::memcpy(&header, nro_data.data(), sizeof(NROHeader));
543 if (!IsValidNRO(header, nro_size, bss_size)) {
544 LOG_ERROR(Service_LDR, "NRO was invalid!");
545 IPC::ResponseBuilder rb{ctx, 2};
546 rb.Push(ERROR_INVALID_NRO);
547 return;
548 }
549
550 // Map memory for the NRO
551 VAddr map_location{};
552 const auto map_result{MapNro(&map_location, system.ApplicationProcess(), nro_address,
553 nro_size, bss_address, bss_size, nro_size + bss_size)};
554 if (map_result != ResultSuccess) {
555 IPC::ResponseBuilder rb{ctx, 2};
556 rb.Push(map_result);
557 }
558
559 // Load the NRO into the mapped memory
560 if (const auto result{
561 LoadNro(system.ApplicationProcess(), header, nro_address, map_location)};
562 result.IsError()) {
563 IPC::ResponseBuilder rb{ctx, 2};
564 rb.Push(result);
565 }
566
567 // Track the loaded NRO
568 nro.insert_or_assign(map_location,
569 NROInfo{hash, map_location, nro_size, bss_address, bss_size,
570 header.segment_headers[TEXT_INDEX].memory_size,
571 header.segment_headers[RO_INDEX].memory_size,
572 header.segment_headers[DATA_INDEX].memory_size, nro_address});
573
574 IPC::ResponseBuilder rb{ctx, 4};
575 rb.Push(ResultSuccess);
576 rb.Push(map_location);
577 }
578
579 Result UnmapNro(const NROInfo& info) {
580 // Each region must be unmapped separately to validate memory state
581 auto& page_table{system.ApplicationProcess()->GetPageTable()};
582
583 if (info.bss_size != 0) {
584 R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size +
585 info.data_size,
586 info.bss_address, info.bss_size));
587 }
588
589 R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size,
590 info.src_addr + info.text_size + info.ro_size,
591 info.data_size));
592 R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size,
593 info.src_addr + info.text_size, info.ro_size));
594 R_TRY(page_table.UnmapCodeMemory(info.nro_address, info.src_addr, info.text_size));
595 return ResultSuccess;
596 }
597
598 void UnloadModule(HLERequestContext& ctx) {
599 if (!initialized) {
600 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
601 IPC::ResponseBuilder rb{ctx, 2};
602 rb.Push(ERROR_NOT_INITIALIZED);
603 return;
604 }
605
606 struct Parameters {
607 u64_le process_id;
608 u64_le nro_address;
609 };
610
611 IPC::RequestParser rp{ctx};
612 const auto [process_id, nro_address] = rp.PopRaw<Parameters>();
613 LOG_DEBUG(Service_LDR, "called with process_id={:016X}, nro_address=0x{:016X}", process_id,
614 nro_address);
615
616 if (!Common::Is4KBAligned(nro_address)) {
617 LOG_ERROR(Service_LDR, "NRO address has invalid alignment (nro_address=0x{:016X})",
618 nro_address);
619 IPC::ResponseBuilder rb{ctx, 2};
620 rb.Push(ERROR_INVALID_ALIGNMENT);
621 return;
622 }
623
624 const auto iter = nro.find(nro_address);
625 if (iter == nro.end()) {
626 LOG_ERROR(Service_LDR,
627 "The NRO attempting to be unmapped was not mapped or has an invalid address "
628 "(nro_address=0x{:016X})!",
629 nro_address);
630 IPC::ResponseBuilder rb{ctx, 2};
631 rb.Push(ERROR_INVALID_NRO_ADDRESS);
632 return;
633 }
634
635 const auto result{UnmapNro(iter->second)};
636
637 nro.erase(iter);
638
639 IPC::ResponseBuilder rb{ctx, 2};
640
641 rb.Push(result);
642 }
643
644 void Initialize(HLERequestContext& ctx) {
645 LOG_WARNING(Service_LDR, "(STUBBED) called");
646
647 initialized = true;
648 current_map_addr =
649 GetInteger(system.ApplicationProcess()->GetPageTable().GetAliasCodeRegionStart());
650
651 IPC::ResponseBuilder rb{ctx, 2};
652 rb.Push(ResultSuccess);
653 }
654
655private:
656 bool initialized{};
657
658 std::map<VAddr, NROInfo> nro;
659 std::map<VAddr, std::vector<SHA256Hash>> nrr;
660 VAddr current_map_addr{};
661
662 bool IsValidNROHash(const SHA256Hash& hash) const {
663 return std::any_of(nrr.begin(), nrr.end(), [&hash](const auto& p) {
664 return std::find(p.second.begin(), p.second.end(), hash) != p.second.end();
665 });
666 }
667
668 static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
669 return header.magic == Common::MakeMagic('N', 'R', 'O', '0') &&
670 header.nro_size == nro_size && header.bss_size == bss_size &&
671
672 header.segment_headers[RO_INDEX].memory_offset ==
673 header.segment_headers[TEXT_INDEX].memory_offset +
674 header.segment_headers[TEXT_INDEX].memory_size &&
675
676 header.segment_headers[DATA_INDEX].memory_offset ==
677 header.segment_headers[RO_INDEX].memory_offset +
678 header.segment_headers[RO_INDEX].memory_size &&
679
680 nro_size == header.segment_headers[DATA_INDEX].memory_offset +
681 header.segment_headers[DATA_INDEX].memory_size &&
682
683 Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size) &&
684 Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) &&
685 Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size);
686 }
687};
688
689void LoopProcess(Core::System& system) { 56void LoopProcess(Core::System& system) {
690 auto server_manager = std::make_unique<ServerManager>(system); 57 auto server_manager = std::make_unique<ServerManager>(system);
691 58
692 server_manager->RegisterNamedService("ldr:dmnt", std::make_shared<DebugMonitor>(system)); 59 server_manager->RegisterNamedService("ldr:dmnt", std::make_shared<DebugMonitor>(system));
693 server_manager->RegisterNamedService("ldr:pm", std::make_shared<ProcessManager>(system)); 60 server_manager->RegisterNamedService("ldr:pm", std::make_shared<ProcessManager>(system));
694 server_manager->RegisterNamedService("ldr:shel", std::make_shared<Shell>(system)); 61 server_manager->RegisterNamedService("ldr:shel", std::make_shared<Shell>(system));
695 server_manager->RegisterNamedService("ldr:ro", std::make_shared<RelocatableObject>(system));
696 62
697 ServerManager::RunServer(std::move(server_manager)); 63 ServerManager::RunServer(std::move(server_manager));
698} 64}
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 d7db24f42..75bf31e32 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -171,6 +171,7 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han
171 buffer->height = SharedBufferHeight; 171 buffer->height = SharedBufferHeight;
172 buffer->stride = SharedBufferBlockLinearStride; 172 buffer->stride = SharedBufferBlockLinearStride;
173 buffer->format = SharedBufferBlockLinearFormat; 173 buffer->format = SharedBufferBlockLinearFormat;
174 buffer->external_format = SharedBufferBlockLinearFormat;
174 buffer->buffer_id = handle; 175 buffer->buffer_id = handle;
175 buffer->offset = slot * SharedBufferSlotSize; 176 buffer->offset = slot * SharedBufferSlotSize;
176 ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError); 177 ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp
new file mode 100644
index 000000000..17110d3f1
--- /dev/null
+++ b/src/core/hle/service/ro/ro.cpp
@@ -0,0 +1,709 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <mbedtls/sha256.h>
5
6#include "common/scope_exit.h"
7#include "core/hle/kernel/k_process.h"
8
9#include "core/hle/service/ipc_helpers.h"
10#include "core/hle/service/ro/ro.h"
11#include "core/hle/service/ro/ro_nro_utils.h"
12#include "core/hle/service/ro/ro_results.h"
13#include "core/hle/service/ro/ro_types.h"
14#include "core/hle/service/server_manager.h"
15#include "core/hle/service/service.h"
16
17namespace Service::RO {
18
19namespace {
20
21// Convenience definitions.
22constexpr size_t MaxSessions = 0x3;
23constexpr size_t MaxNrrInfos = 0x40;
24constexpr size_t MaxNroInfos = 0x40;
25
26constexpr u64 InvalidProcessId = 0xffffffffffffffffULL;
27constexpr u64 InvalidContextId = 0xffffffffffffffffULL;
28
29// Types.
30using Sha256Hash = std::array<u8, 32>;
31
32struct NroInfo {
33 u64 base_address;
34 u64 nro_heap_address;
35 u64 nro_heap_size;
36 u64 bss_heap_address;
37 u64 bss_heap_size;
38 u64 code_size;
39 u64 rw_size;
40 ModuleId module_id;
41};
42
43struct NrrInfo {
44 u64 nrr_heap_address;
45 u64 nrr_heap_size;
46
47 // Verification.
48 std::vector<Sha256Hash> hashes;
49};
50
51struct ProcessContext {
52 constexpr ProcessContext() = default;
53
54 void Initialize(Kernel::KProcess* process, u64 process_id) {
55 ASSERT(!m_in_use);
56
57 m_nro_in_use = {};
58 m_nrr_in_use = {};
59 m_nro_infos = {};
60 m_nrr_infos = {};
61
62 m_process = process;
63 m_process_id = process_id;
64 m_in_use = true;
65
66 if (m_process) {
67 m_process->Open();
68 }
69 }
70
71 void Finalize() {
72 ASSERT(m_in_use);
73
74 if (m_process) {
75 m_process->Close();
76 }
77
78 m_nro_in_use = {};
79 m_nrr_in_use = {};
80 m_nro_infos = {};
81 m_nrr_infos = {};
82
83 m_process = nullptr;
84 m_process_id = InvalidProcessId;
85 m_in_use = false;
86 }
87
88 Kernel::KProcess* GetProcess() const {
89 return m_process;
90 }
91
92 u64 GetProcessId() const {
93 return m_process_id;
94 }
95
96 bool IsFree() const {
97 return !m_in_use;
98 }
99
100 u64 GetProgramId(Kernel::KProcess* other_process) const {
101 // Automatically select a handle, allowing for override.
102 if (other_process) {
103 return other_process->GetProgramId();
104 } else if (m_process) {
105 return m_process->GetProgramId();
106 } else {
107 return 0;
108 }
109 }
110
111 Result GetNrrInfoByAddress(NrrInfo** out, u64 nrr_heap_address) {
112 for (size_t i = 0; i < MaxNrrInfos; i++) {
113 if (m_nrr_in_use[i] && m_nrr_infos[i].nrr_heap_address == nrr_heap_address) {
114 if (out != nullptr) {
115 *out = std::addressof(m_nrr_infos[i]);
116 }
117 R_SUCCEED();
118 }
119 }
120 R_THROW(RO::ResultNotRegistered);
121 }
122
123 Result GetFreeNrrInfo(NrrInfo** out) {
124 for (size_t i = 0; i < MaxNrrInfos; i++) {
125 if (!m_nrr_in_use[i]) {
126 if (out != nullptr) {
127 *out = std::addressof(m_nrr_infos[i]);
128 }
129 R_SUCCEED();
130 }
131 }
132 R_THROW(RO::ResultTooManyNrr);
133 }
134
135 Result GetNroInfoByAddress(NroInfo** out, u64 nro_address) {
136 for (size_t i = 0; i < MaxNroInfos; i++) {
137 if (m_nro_in_use[i] && m_nro_infos[i].base_address == nro_address) {
138 if (out != nullptr) {
139 *out = std::addressof(m_nro_infos[i]);
140 }
141 R_SUCCEED();
142 }
143 }
144 R_THROW(RO::ResultNotLoaded);
145 }
146
147 Result GetNroInfoByModuleId(NroInfo** out, const ModuleId* module_id) {
148 for (size_t i = 0; i < MaxNroInfos; i++) {
149 if (m_nro_in_use[i] && std::memcmp(std::addressof(m_nro_infos[i].module_id), module_id,
150 sizeof(*module_id)) == 0) {
151 if (out != nullptr) {
152 *out = std::addressof(m_nro_infos[i]);
153 }
154 R_SUCCEED();
155 }
156 }
157 R_THROW(RO::ResultNotLoaded);
158 }
159
160 Result GetFreeNroInfo(NroInfo** out) {
161 for (size_t i = 0; i < MaxNroInfos; i++) {
162 if (!m_nro_in_use[i]) {
163 if (out != nullptr) {
164 *out = std::addressof(m_nro_infos[i]);
165 }
166 R_SUCCEED();
167 }
168 }
169 R_THROW(RO::ResultTooManyNro);
170 }
171
172 Result ValidateHasNroHash(u64 base_address, const NroHeader* nro_header) const {
173 // Calculate hash.
174 Sha256Hash hash;
175 {
176 const u64 size = nro_header->GetSize();
177
178 std::vector<u8> nro_data(size);
179 m_process->GetMemory().ReadBlock(base_address, nro_data.data(), size);
180
181 mbedtls_sha256_ret(nro_data.data(), size, hash.data(), 0);
182 }
183
184 for (size_t i = 0; i < MaxNrrInfos; i++) {
185 // Ensure we only check NRRs that are used.
186 if (!m_nrr_in_use[i]) {
187 continue;
188 }
189
190 // Locate the hash within the hash list.
191 const auto hash_it = std::ranges::find(m_nrr_infos[i].hashes, hash);
192 if (hash_it == m_nrr_infos[i].hashes.end()) {
193 continue;
194 }
195
196 // The hash is valid!
197 R_SUCCEED();
198 }
199
200 R_THROW(RO::ResultNotAuthorized);
201 }
202
203 Result ValidateNro(ModuleId* out_module_id, u64* out_rx_size, u64* out_ro_size,
204 u64* out_rw_size, u64 base_address, u64 expected_nro_size,
205 u64 expected_bss_size) {
206 // Ensure we have a process to work on.
207 R_UNLESS(m_process != nullptr, RO::ResultInvalidProcess);
208
209 // Read the NRO header.
210 NroHeader header{};
211 m_process->GetMemory().ReadBlock(base_address, std::addressof(header), sizeof(header));
212
213 // Validate header.
214 R_UNLESS(header.IsMagicValid(), RO::ResultInvalidNro);
215
216 // Read sizes from header.
217 const u64 nro_size = header.GetSize();
218 const u64 text_ofs = header.GetTextOffset();
219 const u64 text_size = header.GetTextSize();
220 const u64 ro_ofs = header.GetRoOffset();
221 const u64 ro_size = header.GetRoSize();
222 const u64 rw_ofs = header.GetRwOffset();
223 const u64 rw_size = header.GetRwSize();
224 const u64 bss_size = header.GetBssSize();
225
226 // Validate sizes meet expected.
227 R_UNLESS(nro_size == expected_nro_size, RO::ResultInvalidNro);
228 R_UNLESS(bss_size == expected_bss_size, RO::ResultInvalidNro);
229
230 // Validate all sizes are aligned.
231 R_UNLESS(Common::IsAligned(text_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro);
232 R_UNLESS(Common::IsAligned(ro_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro);
233 R_UNLESS(Common::IsAligned(rw_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro);
234 R_UNLESS(Common::IsAligned(bss_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro);
235
236 // Validate sections are in order.
237 R_UNLESS(text_ofs <= ro_ofs, RO::ResultInvalidNro);
238 R_UNLESS(ro_ofs <= rw_ofs, RO::ResultInvalidNro);
239
240 // Validate sections are sequential and contiguous.
241 R_UNLESS(text_ofs == 0, RO::ResultInvalidNro);
242 R_UNLESS(text_ofs + text_size == ro_ofs, RO::ResultInvalidNro);
243 R_UNLESS(ro_ofs + ro_size == rw_ofs, RO::ResultInvalidNro);
244 R_UNLESS(rw_ofs + rw_size == nro_size, RO::ResultInvalidNro);
245
246 // Verify NRO hash.
247 R_TRY(this->ValidateHasNroHash(base_address, std::addressof(header)));
248
249 // Check if NRO has already been loaded.
250 const ModuleId* module_id = header.GetModuleId();
251 R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), RO::ResultAlreadyLoaded);
252
253 // Apply patches to NRO.
254 // LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8*>(mapped_memory), nro_size);
255
256 // Copy to output.
257 *out_module_id = *module_id;
258 *out_rx_size = text_size;
259 *out_ro_size = ro_size;
260 *out_rw_size = rw_size;
261 R_SUCCEED();
262 }
263
264 void SetNrrInfoInUse(const NrrInfo* info, bool in_use) {
265 ASSERT(std::addressof(m_nrr_infos[0]) <= info &&
266 info <= std::addressof(m_nrr_infos[MaxNrrInfos - 1]));
267 const size_t index = info - std::addressof(m_nrr_infos[0]);
268 m_nrr_in_use[index] = in_use;
269 }
270
271 void SetNroInfoInUse(const NroInfo* info, bool in_use) {
272 ASSERT(std::addressof(m_nro_infos[0]) <= info &&
273 info <= std::addressof(m_nro_infos[MaxNroInfos - 1]));
274 const size_t index = info - std::addressof(m_nro_infos[0]);
275 m_nro_in_use[index] = in_use;
276 }
277
278private:
279 std::array<bool, MaxNroInfos> m_nro_in_use{};
280 std::array<bool, MaxNrrInfos> m_nrr_in_use{};
281 std::array<NroInfo, MaxNroInfos> m_nro_infos{};
282 std::array<NrrInfo, MaxNrrInfos> m_nrr_infos{};
283 Kernel::KProcess* m_process{};
284 u64 m_process_id{InvalidProcessId};
285 bool m_in_use{};
286};
287
288Result ValidateAddressAndNonZeroSize(u64 address, u64 size) {
289 R_UNLESS(Common::IsAligned(address, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidAddress);
290 R_UNLESS(size != 0, RO::ResultInvalidSize);
291 R_UNLESS(Common::IsAligned(size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidSize);
292 R_UNLESS(address < address + size, RO::ResultInvalidSize);
293 R_SUCCEED();
294}
295
296Result ValidateAddressAndSize(u64 address, u64 size) {
297 R_UNLESS(Common::IsAligned(address, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidAddress);
298 R_UNLESS(Common::IsAligned(size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidSize);
299 R_UNLESS(size == 0 || address < address + size, RO::ResultInvalidSize);
300 R_SUCCEED();
301}
302
303class RoContext {
304public:
305 explicit RoContext() = default;
306
307 Result RegisterProcess(size_t* out_context_id, Kernel::KProcess* process, u64 process_id) {
308 // Validate process id.
309 R_UNLESS(process->GetProcessId() == process_id, RO::ResultInvalidProcess);
310
311 // Check if a process context already exists.
312 R_UNLESS(this->GetContextByProcessId(process_id) == nullptr, RO::ResultInvalidSession);
313
314 // Allocate a context to manage the process handle.
315 *out_context_id = this->AllocateContext(process, process_id);
316
317 R_SUCCEED();
318 }
319
320 Result ValidateProcess(size_t context_id, u64 process_id) {
321 const ProcessContext* ctx = this->GetContextById(context_id);
322 R_UNLESS(ctx != nullptr, RO::ResultInvalidProcess);
323 R_UNLESS(ctx->GetProcessId() == process_id, RO::ResultInvalidProcess);
324 R_SUCCEED();
325 }
326
327 void UnregisterProcess(size_t context_id) {
328 this->FreeContext(context_id);
329 }
330
331 Result RegisterModuleInfo(size_t context_id, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind,
332 bool enforce_nrr_kind) {
333 // Get context.
334 ProcessContext* context = this->GetContextById(context_id);
335 ASSERT(context != nullptr);
336
337 // Validate address/size.
338 R_TRY(ValidateAddressAndNonZeroSize(nrr_address, nrr_size));
339
340 // Check we have space for a new NRR.
341 NrrInfo* nrr_info = nullptr;
342 R_TRY(context->GetFreeNrrInfo(std::addressof(nrr_info)));
343
344 // Ensure we have a valid process to read from.
345 Kernel::KProcess* process = context->GetProcess();
346 R_UNLESS(process != nullptr, RO::ResultInvalidProcess);
347
348 // Read NRR.
349 NrrHeader header{};
350 process->GetMemory().ReadBlock(nrr_address, std::addressof(header), sizeof(header));
351
352 // Set NRR info.
353 context->SetNrrInfoInUse(nrr_info, true);
354 nrr_info->nrr_heap_address = nrr_address;
355 nrr_info->nrr_heap_size = nrr_size;
356
357 // Read NRR hash list.
358 nrr_info->hashes.resize(header.GetNumHashes());
359 process->GetMemory().ReadBlock(nrr_address + header.GetHashesOffset(),
360 nrr_info->hashes.data(),
361 sizeof(Sha256Hash) * header.GetNumHashes());
362
363 R_SUCCEED();
364 }
365
366 Result UnregisterModuleInfo(size_t context_id, u64 nrr_address) {
367 // Get context.
368 ProcessContext* context = this->GetContextById(context_id);
369 ASSERT(context != nullptr);
370
371 // Validate address.
372 R_UNLESS(Common::IsAligned(nrr_address, Core::Memory::YUZU_PAGESIZE),
373 RO::ResultInvalidAddress);
374
375 // Check the NRR is loaded.
376 NrrInfo* nrr_info = nullptr;
377 R_TRY(context->GetNrrInfoByAddress(std::addressof(nrr_info), nrr_address));
378
379 // Nintendo does this unconditionally, whether or not the actual unmap succeeds.
380 context->SetNrrInfoInUse(nrr_info, false);
381 *nrr_info = {};
382
383 R_SUCCEED();
384 }
385
386 Result MapManualLoadModuleMemory(u64* out_address, size_t context_id, u64 nro_address,
387 u64 nro_size, u64 bss_address, u64 bss_size) {
388 // Get context.
389 ProcessContext* context = this->GetContextById(context_id);
390 ASSERT(context != nullptr);
391
392 // Validate address/size.
393 R_TRY(ValidateAddressAndNonZeroSize(nro_address, nro_size));
394 R_TRY(ValidateAddressAndSize(bss_address, bss_size));
395
396 const u64 total_size = nro_size + bss_size;
397 R_UNLESS(total_size >= nro_size, RO::ResultInvalidSize);
398 R_UNLESS(total_size >= bss_size, RO::ResultInvalidSize);
399
400 // Check we have space for a new NRO.
401 NroInfo* nro_info = nullptr;
402 R_TRY(context->GetFreeNroInfo(std::addressof(nro_info)));
403 nro_info->nro_heap_address = nro_address;
404 nro_info->nro_heap_size = nro_size;
405 nro_info->bss_heap_address = bss_address;
406 nro_info->bss_heap_size = bss_size;
407
408 // Map the NRO.
409 R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcess(), nro_address,
410 nro_size, bss_address, bss_size, generate_random));
411 ON_RESULT_FAILURE {
412 UnmapNro(context->GetProcess(), nro_info->base_address, nro_address, nro_size,
413 bss_address, bss_size);
414 };
415
416 // Validate the NRO (parsing region extents).
417 u64 rx_size = 0, ro_size = 0, rw_size = 0;
418 R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size),
419 std::addressof(ro_size), std::addressof(rw_size),
420 nro_info->base_address, nro_size, bss_size));
421
422 // Set NRO perms.
423 R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size,
424 rw_size + bss_size));
425
426 context->SetNroInfoInUse(nro_info, true);
427 nro_info->code_size = rx_size + ro_size;
428 nro_info->rw_size = rw_size;
429 *out_address = nro_info->base_address;
430 R_SUCCEED();
431 }
432
433 Result UnmapManualLoadModuleMemory(size_t context_id, u64 nro_address) {
434 // Get context.
435 ProcessContext* context = this->GetContextById(context_id);
436 ASSERT(context != nullptr);
437
438 // Validate address.
439 R_UNLESS(Common::IsAligned(nro_address, Core::Memory::YUZU_PAGESIZE),
440 RO::ResultInvalidAddress);
441
442 // Check the NRO is loaded.
443 NroInfo* nro_info = nullptr;
444 R_TRY(context->GetNroInfoByAddress(std::addressof(nro_info), nro_address));
445
446 // Unmap.
447 const NroInfo nro_backup = *nro_info;
448 {
449 // Nintendo does this unconditionally, whether or not the actual unmap succeeds.
450 context->SetNroInfoInUse(nro_info, false);
451 std::memset(nro_info, 0, sizeof(*nro_info));
452 }
453 R_RETURN(UnmapNro(context->GetProcess(), nro_backup.base_address,
454 nro_backup.nro_heap_address, nro_backup.code_size + nro_backup.rw_size,
455 nro_backup.bss_heap_address, nro_backup.bss_heap_size));
456 }
457
458private:
459 std::array<ProcessContext, MaxSessions> process_contexts;
460 std::mt19937_64 generate_random;
461
462 // Context Helpers.
463 ProcessContext* GetContextById(size_t context_id) {
464 if (context_id == InvalidContextId) {
465 return nullptr;
466 }
467
468 ASSERT(context_id < process_contexts.size());
469 return std::addressof(process_contexts[context_id]);
470 }
471
472 ProcessContext* GetContextByProcessId(u64 process_id) {
473 for (size_t i = 0; i < MaxSessions; i++) {
474 if (process_contexts[i].GetProcessId() == process_id) {
475 return std::addressof(process_contexts[i]);
476 }
477 }
478 return nullptr;
479 }
480
481 size_t AllocateContext(Kernel::KProcess* process, u64 process_id) {
482 // Find a free process context.
483 for (size_t i = 0; i < MaxSessions; i++) {
484 ProcessContext* context = std::addressof(process_contexts[i]);
485
486 if (context->IsFree()) {
487 context->Initialize(process, process_id);
488 return i;
489 }
490 }
491
492 // Failure to find a free context is actually an abort condition.
493 UNREACHABLE();
494 }
495
496 void FreeContext(size_t context_id) {
497 if (ProcessContext* context = GetContextById(context_id); context != nullptr) {
498 context->Finalize();
499 }
500 }
501};
502
503class RoInterface {
504public:
505 explicit RoInterface(std::shared_ptr<RoContext> ro, NrrKind nrr_kind)
506 : m_ro(ro), m_context_id(InvalidContextId), m_nrr_kind(nrr_kind) {}
507 ~RoInterface() {
508 m_ro->UnregisterProcess(m_context_id);
509 }
510
511 Result MapManualLoadModuleMemory(u64* out_load_address, u64 client_pid, u64 nro_address,
512 u64 nro_size, u64 bss_address, u64 bss_size) {
513 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
514 R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address, m_context_id, nro_address,
515 nro_size, bss_address, bss_size));
516 }
517
518 Result UnmapManualLoadModuleMemory(u64 client_pid, u64 nro_address) {
519 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
520 R_RETURN(m_ro->UnmapManualLoadModuleMemory(m_context_id, nro_address));
521 }
522
523 Result RegisterModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size) {
524 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
525 R_RETURN(
526 m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, NrrKind::User, true));
527 }
528
529 Result UnregisterModuleInfo(u64 client_pid, u64 nrr_address) {
530 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
531 R_RETURN(m_ro->UnregisterModuleInfo(m_context_id, nrr_address));
532 }
533
534 Result RegisterProcessHandle(u64 client_pid, Kernel::KProcess* process) {
535 // Register the process.
536 R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process, client_pid));
537 }
538
539 Result RegisterProcessModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size,
540 Kernel::KProcess* process) {
541 // Validate the process.
542 R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
543
544 // Register the module.
545 R_RETURN(m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, m_nrr_kind,
546 m_nrr_kind == NrrKind::JitPlugin));
547 }
548
549private:
550 std::shared_ptr<RoContext> m_ro{};
551 size_t m_context_id{};
552 NrrKind m_nrr_kind{};
553};
554
555class IRoInterface : public ServiceFramework<IRoInterface> {
556public:
557 explicit IRoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro,
558 NrrKind nrr_kind)
559 : ServiceFramework{system_, name_}, interface {
560 ro, nrr_kind
561 } {
562 // clang-format off
563 static const FunctionInfo functions[] = {
564 {0, &IRoInterface::MapManualLoadModuleMemory, "MapManualLoadModuleMemory"},
565 {1, &IRoInterface::UnmapManualLoadModuleMemory, "UnmapManualLoadModuleMemory"},
566 {2, &IRoInterface::RegisterModuleInfo, "RegisterModuleInfo"},
567 {3, &IRoInterface::UnregisterModuleInfo, "UnregisterModuleInfo"},
568 {4, &IRoInterface::RegisterProcessHandle, "RegisterProcessHandle"},
569 {10, &IRoInterface::RegisterProcessModuleInfo, "RegisterProcessModuleInfo"},
570 };
571 // clang-format on
572
573 RegisterHandlers(functions);
574 }
575
576private:
577 void MapManualLoadModuleMemory(HLERequestContext& ctx) {
578 LOG_DEBUG(Service_LDR, "(called)");
579
580 struct InputParameters {
581 u64 client_pid;
582 u64 nro_address;
583 u64 nro_size;
584 u64 bss_address;
585 u64 bss_size;
586 };
587
588 IPC::RequestParser rp{ctx};
589 auto params = rp.PopRaw<InputParameters>();
590
591 u64 load_address = 0;
592 auto result = interface.MapManualLoadModuleMemory(&load_address, ctx.GetPID(),
593 params.nro_address, params.nro_size,
594 params.bss_address, params.bss_size);
595
596 IPC::ResponseBuilder rb{ctx, 4};
597 rb.Push(result);
598 rb.Push(load_address);
599 }
600
601 void UnmapManualLoadModuleMemory(HLERequestContext& ctx) {
602 LOG_DEBUG(Service_LDR, "(called)");
603
604 struct InputParameters {
605 u64 client_pid;
606 u64 nro_address;
607 };
608
609 IPC::RequestParser rp{ctx};
610 auto params = rp.PopRaw<InputParameters>();
611 auto result = interface.UnmapManualLoadModuleMemory(ctx.GetPID(), params.nro_address);
612
613 IPC::ResponseBuilder rb{ctx, 2};
614 rb.Push(result);
615 }
616
617 void RegisterModuleInfo(HLERequestContext& ctx) {
618 LOG_DEBUG(Service_LDR, "(called)");
619
620 struct InputParameters {
621 u64 client_pid;
622 u64 nrr_address;
623 u64 nrr_size;
624 };
625
626 IPC::RequestParser rp{ctx};
627 auto params = rp.PopRaw<InputParameters>();
628 auto result =
629 interface.RegisterModuleInfo(ctx.GetPID(), params.nrr_address, params.nrr_size);
630
631 IPC::ResponseBuilder rb{ctx, 2};
632 rb.Push(result);
633 }
634
635 void UnregisterModuleInfo(HLERequestContext& ctx) {
636 LOG_DEBUG(Service_LDR, "(called)");
637
638 struct InputParameters {
639 u64 client_pid;
640 u64 nrr_address;
641 };
642
643 IPC::RequestParser rp{ctx};
644 auto params = rp.PopRaw<InputParameters>();
645 auto result = interface.UnregisterModuleInfo(ctx.GetPID(), params.nrr_address);
646
647 IPC::ResponseBuilder rb{ctx, 2};
648 rb.Push(result);
649 }
650
651 void RegisterProcessHandle(HLERequestContext& ctx) {
652 LOG_DEBUG(Service_LDR, "(called)");
653
654 auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
655 auto client_pid = ctx.GetPID();
656 auto result = interface.RegisterProcessHandle(client_pid,
657 process_h->DynamicCast<Kernel::KProcess*>());
658
659 IPC::ResponseBuilder rb{ctx, 2};
660 rb.Push(result);
661 }
662
663 void RegisterProcessModuleInfo(HLERequestContext& ctx) {
664 LOG_DEBUG(Service_LDR, "(called)");
665
666 struct InputParameters {
667 u64 client_pid;
668 u64 nrr_address;
669 u64 nrr_size;
670 };
671
672 IPC::RequestParser rp{ctx};
673 auto params = rp.PopRaw<InputParameters>();
674 auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
675
676 auto client_pid = ctx.GetPID();
677 auto result =
678 interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size,
679 process_h->DynamicCast<Kernel::KProcess*>());
680
681 IPC::ResponseBuilder rb{ctx, 2};
682 rb.Push(result);
683 }
684
685 RoInterface interface;
686};
687
688} // namespace
689
690void LoopProcess(Core::System& system) {
691 auto server_manager = std::make_unique<ServerManager>(system);
692
693 auto ro = std::make_shared<RoContext>();
694
695 const auto RoInterfaceFactoryForUser = [&, ro] {
696 return std::make_shared<IRoInterface>(system, "ldr:ro", ro, NrrKind::User);
697 };
698
699 const auto RoInterfaceFactoryForJitPlugin = [&, ro] {
700 return std::make_shared<IRoInterface>(system, "ro:1", ro, NrrKind::JitPlugin);
701 };
702
703 server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser));
704 server_manager->RegisterNamedService("ro:1", std::move(RoInterfaceFactoryForJitPlugin));
705
706 ServerManager::RunServer(std::move(server_manager));
707}
708
709} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro.h b/src/core/hle/service/ro/ro.h
new file mode 100644
index 000000000..74dc08536
--- /dev/null
+++ b/src/core/hle/service/ro/ro.h
@@ -0,0 +1,14 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6namespace Core {
7class System;
8}
9
10namespace Service::RO {
11
12void LoopProcess(Core::System& system);
13
14} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro_nro_utils.cpp b/src/core/hle/service/ro/ro_nro_utils.cpp
new file mode 100644
index 000000000..268c7f93e
--- /dev/null
+++ b/src/core/hle/service/ro/ro_nro_utils.cpp
@@ -0,0 +1,185 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_process.h"
5#include "core/hle/service/ro/ro_nro_utils.h"
6#include "core/hle/service/ro/ro_results.h"
7
8namespace Service::RO {
9
10namespace {
11
12struct ProcessMemoryRegion {
13 u64 address;
14 u64 size;
15};
16
17size_t GetTotalProcessMemoryRegionSize(const ProcessMemoryRegion* regions, size_t num_regions) {
18 size_t total = 0;
19
20 for (size_t i = 0; i < num_regions; ++i) {
21 total += regions[i].size;
22 }
23
24 return total;
25}
26
27size_t SetupNroProcessMemoryRegions(ProcessMemoryRegion* regions, u64 nro_heap_address,
28 u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size) {
29 // Reset region count.
30 size_t num_regions = 0;
31
32 // We always want a region for the nro.
33 regions[num_regions++] = {nro_heap_address, nro_heap_size};
34
35 // If we have bss, create a region for bss.
36 if (bss_heap_size > 0) {
37 regions[num_regions++] = {bss_heap_address, bss_heap_size};
38 }
39
40 return num_regions;
41}
42
43Result SetProcessMemoryPermission(Kernel::KProcess* process, u64 address, u64 size,
44 Kernel::Svc::MemoryPermission permission) {
45 auto& page_table = process->GetPageTable();
46
47 // Set permission.
48 R_RETURN(page_table.SetProcessMemoryPermission(address, size, permission));
49}
50
51Result UnmapProcessCodeMemory(Kernel::KProcess* process, u64 process_code_address,
52 const ProcessMemoryRegion* regions, size_t num_regions) {
53 // Get the total process memory region size.
54 const size_t total_size = GetTotalProcessMemoryRegionSize(regions, num_regions);
55
56 auto& page_table = process->GetPageTable();
57
58 // Unmap each region in order.
59 size_t cur_offset = total_size;
60 for (size_t i = 0; i < num_regions; ++i) {
61 // We want to unmap in reverse order.
62 const auto& cur_region = regions[num_regions - 1 - i];
63
64 // Subtract to update the current offset.
65 cur_offset -= cur_region.size;
66
67 // Unmap.
68 R_TRY(page_table.UnmapCodeMemory(process_code_address + cur_offset, cur_region.address,
69 cur_region.size));
70 }
71
72 R_SUCCEED();
73}
74
75Result EnsureGuardPages(Kernel::KProcessPageTable& page_table, u64 map_address, u64 map_size) {
76 Kernel::KMemoryInfo memory_info;
77 Kernel::Svc::PageInfo page_info;
78
79 // Ensure page before mapping is unmapped.
80 R_TRY(page_table.QueryInfo(std::addressof(memory_info), std::addressof(page_info),
81 map_address - 1));
82 R_UNLESS(memory_info.GetSvcState() == Kernel::Svc::MemoryState::Free,
83 Kernel::ResultInvalidState);
84
85 // Ensure page after mapping is unmapped.
86 R_TRY(page_table.QueryInfo(std::addressof(memory_info), std::addressof(page_info),
87 map_address + map_size));
88 R_UNLESS(memory_info.GetSvcState() == Kernel::Svc::MemoryState::Free,
89 Kernel::ResultInvalidState);
90
91 // Successfully verified guard pages.
92 R_SUCCEED();
93}
94
95Result MapProcessCodeMemory(u64* out, Kernel::KProcess* process, const ProcessMemoryRegion* regions,
96 size_t num_regions, std::mt19937_64& generate_random) {
97 auto& page_table = process->GetPageTable();
98 const u64 alias_code_start =
99 GetInteger(page_table.GetAliasCodeRegionStart()) / Kernel::PageSize;
100 const u64 alias_code_size = page_table.GetAliasCodeRegionSize() / Kernel::PageSize;
101
102 for (size_t trial = 0; trial < 64; trial++) {
103 // Generate a new trial address.
104 const u64 mapped_address =
105 (alias_code_start + (generate_random() % alias_code_size)) * Kernel::PageSize;
106
107 const auto MapRegions = [&] {
108 // Map the regions in order.
109 u64 mapped_size = 0;
110 for (size_t i = 0; i < num_regions; ++i) {
111 // If we fail, unmap up to where we've mapped.
112 ON_RESULT_FAILURE {
113 R_ASSERT(UnmapProcessCodeMemory(process, mapped_address, regions, i));
114 };
115
116 // Map the current region.
117 R_TRY(page_table.MapCodeMemory(mapped_address + mapped_size, regions[i].address,
118 regions[i].size));
119
120 mapped_size += regions[i].size;
121 }
122
123 // If we fail, unmap all mapped regions.
124 ON_RESULT_FAILURE {
125 R_ASSERT(UnmapProcessCodeMemory(process, mapped_address, regions, num_regions));
126 };
127
128 // Ensure guard pages.
129 R_RETURN(EnsureGuardPages(page_table, mapped_address, mapped_size));
130 };
131
132 if (R_SUCCEEDED(MapRegions())) {
133 // Set the output address.
134 *out = mapped_address;
135 R_SUCCEED();
136 }
137 }
138
139 // We failed to map anything.
140 R_THROW(RO::ResultOutOfAddressSpace);
141}
142
143} // namespace
144
145Result MapNro(u64* out_base_address, Kernel::KProcess* process, u64 nro_heap_address,
146 u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size,
147 std::mt19937_64& generate_random) {
148 // Set up the process memory regions.
149 std::array<ProcessMemoryRegion, 2> regions{};
150 const size_t num_regions = SetupNroProcessMemoryRegions(
151 regions.data(), nro_heap_address, nro_heap_size, bss_heap_address, bss_heap_size);
152
153 // Re-map the nro/bss as code memory in the destination process.
154 R_RETURN(MapProcessCodeMemory(out_base_address, process, regions.data(), num_regions,
155 generate_random));
156}
157
158Result SetNroPerms(Kernel::KProcess* process, u64 base_address, u64 rx_size, u64 ro_size,
159 u64 rw_size) {
160 const u64 rx_offset = 0;
161 const u64 ro_offset = rx_offset + rx_size;
162 const u64 rw_offset = ro_offset + ro_size;
163
164 R_TRY(SetProcessMemoryPermission(process, base_address + rx_offset, rx_size,
165 Kernel::Svc::MemoryPermission::ReadExecute));
166 R_TRY(SetProcessMemoryPermission(process, base_address + ro_offset, ro_size,
167 Kernel::Svc::MemoryPermission::Read));
168 R_TRY(SetProcessMemoryPermission(process, base_address + rw_offset, rw_size,
169 Kernel::Svc::MemoryPermission::ReadWrite));
170
171 R_SUCCEED();
172}
173
174Result UnmapNro(Kernel::KProcess* process, u64 base_address, u64 nro_heap_address,
175 u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size) {
176 // Set up the process memory regions.
177 std::array<ProcessMemoryRegion, 2> regions{};
178 const size_t num_regions = SetupNroProcessMemoryRegions(
179 regions.data(), nro_heap_address, nro_heap_size, bss_heap_address, bss_heap_size);
180
181 // Unmap the nro/bss.
182 R_RETURN(UnmapProcessCodeMemory(process, base_address, regions.data(), num_regions));
183}
184
185} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro_nro_utils.h b/src/core/hle/service/ro/ro_nro_utils.h
new file mode 100644
index 000000000..f7083a1ba
--- /dev/null
+++ b/src/core/hle/service/ro/ro_nro_utils.h
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <random>
7
8#include "common/common_types.h"
9
10namespace Kernel {
11class KProcess;
12}
13
14union Result;
15
16namespace Service::RO {
17
18Result MapNro(u64* out_base_address, Kernel::KProcess* process, u64 nro_heap_address,
19 u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size,
20 std::mt19937_64& generate_random);
21Result SetNroPerms(Kernel::KProcess* process, u64 base_address, u64 rx_size, u64 ro_size,
22 u64 rw_size);
23Result UnmapNro(Kernel::KProcess* process, u64 base_address, u64 nro_heap_address,
24 u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size);
25
26} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro_results.h b/src/core/hle/service/ro/ro_results.h
new file mode 100644
index 000000000..00f05c5a5
--- /dev/null
+++ b/src/core/hle/service/ro/ro_results.h
@@ -0,0 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/result.h"
5
6namespace Service::RO {
7
8constexpr Result ResultOutOfAddressSpace{ErrorModule::RO, 2};
9constexpr Result ResultAlreadyLoaded{ErrorModule::RO, 3};
10constexpr Result ResultInvalidNro{ErrorModule::RO, 4};
11constexpr Result ResultInvalidNrr{ErrorModule::RO, 6};
12constexpr Result ResultTooManyNro{ErrorModule::RO, 7};
13constexpr Result ResultTooManyNrr{ErrorModule::RO, 8};
14constexpr Result ResultNotAuthorized{ErrorModule::RO, 9};
15constexpr Result ResultInvalidNrrKind{ErrorModule::RO, 10};
16constexpr Result ResultInternalError{ErrorModule::RO, 1023};
17constexpr Result ResultInvalidAddress{ErrorModule::RO, 1025};
18constexpr Result ResultInvalidSize{ErrorModule::RO, 1026};
19constexpr Result ResultNotLoaded{ErrorModule::RO, 1028};
20constexpr Result ResultNotRegistered{ErrorModule::RO, 1029};
21constexpr Result ResultInvalidSession{ErrorModule::RO, 1030};
22constexpr Result ResultInvalidProcess{ErrorModule::RO, 1031};
23
24} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro_types.h b/src/core/hle/service/ro/ro_types.h
new file mode 100644
index 000000000..624d52ee5
--- /dev/null
+++ b/src/core/hle/service/ro/ro_types.h
@@ -0,0 +1,181 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/assert.h"
5#include "common/common_funcs.h"
6#include "common/common_types.h"
7
8namespace Service::RO {
9
10enum class NrrKind : u8 {
11 User = 0,
12 JitPlugin = 1,
13 Count,
14};
15
16static constexpr size_t ModuleIdSize = 0x20;
17struct ModuleId {
18 std::array<u8, ModuleIdSize> data;
19};
20static_assert(sizeof(ModuleId) == ModuleIdSize);
21
22struct NrrCertification {
23 static constexpr size_t RsaKeySize = 0x100;
24 static constexpr size_t SignedSize = 0x120;
25
26 u64 program_id_mask;
27 u64 program_id_pattern;
28 std::array<u8, 0x10> reserved_10;
29 std::array<u8, RsaKeySize> modulus;
30 std::array<u8, RsaKeySize> signature;
31};
32static_assert(sizeof(NrrCertification) ==
33 NrrCertification::RsaKeySize + NrrCertification::SignedSize);
34
35class NrrHeader {
36public:
37 static constexpr u32 Magic = Common::MakeMagic('N', 'R', 'R', '0');
38
39public:
40 bool IsMagicValid() const {
41 return m_magic == Magic;
42 }
43
44 bool IsProgramIdValid() const {
45 return (m_program_id & m_certification.program_id_mask) ==
46 m_certification.program_id_pattern;
47 }
48
49 NrrKind GetNrrKind() const {
50 const NrrKind kind = static_cast<NrrKind>(m_nrr_kind);
51 ASSERT(kind < NrrKind::Count);
52 return kind;
53 }
54
55 u64 GetProgramId() const {
56 return m_program_id;
57 }
58
59 u32 GetSize() const {
60 return m_size;
61 }
62
63 u32 GetNumHashes() const {
64 return m_num_hashes;
65 }
66
67 size_t GetHashesOffset() const {
68 return m_hashes_offset;
69 }
70
71 u32 GetKeyGeneration() const {
72 return m_key_generation;
73 }
74
75 const u8* GetCertificationSignature() const {
76 return m_certification.signature.data();
77 }
78
79 const u8* GetCertificationSignedArea() const {
80 return reinterpret_cast<const u8*>(std::addressof(m_certification));
81 }
82
83 const u8* GetCertificationModulus() const {
84 return m_certification.modulus.data();
85 }
86
87 const u8* GetSignature() const {
88 return m_signature.data();
89 }
90
91 size_t GetSignedAreaSize() const {
92 return m_size - GetSignedAreaOffset();
93 }
94
95 static constexpr size_t GetSignedAreaOffset() {
96 return offsetof(NrrHeader, m_program_id);
97 }
98
99private:
100 u32 m_magic;
101 u32 m_key_generation;
102 INSERT_PADDING_BYTES_NOINIT(8);
103 NrrCertification m_certification;
104 std::array<u8, 0x100> m_signature;
105 u64 m_program_id;
106 u32 m_size;
107 u8 m_nrr_kind; // 7.0.0+
108 INSERT_PADDING_BYTES_NOINIT(3);
109 u32 m_hashes_offset;
110 u32 m_num_hashes;
111 INSERT_PADDING_BYTES_NOINIT(8);
112};
113static_assert(sizeof(NrrHeader) == 0x350, "NrrHeader has wrong size");
114
115class NroHeader {
116public:
117 static constexpr u32 Magic = Common::MakeMagic('N', 'R', 'O', '0');
118
119public:
120 bool IsMagicValid() const {
121 return m_magic == Magic;
122 }
123
124 u32 GetSize() const {
125 return m_size;
126 }
127
128 u32 GetTextOffset() const {
129 return m_text_offset;
130 }
131
132 u32 GetTextSize() const {
133 return m_text_size;
134 }
135
136 u32 GetRoOffset() const {
137 return m_ro_offset;
138 }
139
140 u32 GetRoSize() const {
141 return m_ro_size;
142 }
143
144 u32 GetRwOffset() const {
145 return m_rw_offset;
146 }
147
148 u32 GetRwSize() const {
149 return m_rw_size;
150 }
151
152 u32 GetBssSize() const {
153 return m_bss_size;
154 }
155
156 const ModuleId* GetModuleId() const {
157 return std::addressof(m_module_id);
158 }
159
160private:
161 u32 m_entrypoint_insn;
162 u32 m_mod_offset;
163 INSERT_PADDING_BYTES_NOINIT(0x8);
164 u32 m_magic;
165 INSERT_PADDING_BYTES_NOINIT(0x4);
166 u32 m_size;
167 INSERT_PADDING_BYTES_NOINIT(0x4);
168 u32 m_text_offset;
169 u32 m_text_size;
170 u32 m_ro_offset;
171 u32 m_ro_size;
172 u32 m_rw_offset;
173 u32 m_rw_size;
174 u32 m_bss_size;
175 INSERT_PADDING_BYTES_NOINIT(0x4);
176 ModuleId m_module_id;
177 INSERT_PADDING_BYTES_NOINIT(0x20);
178};
179static_assert(sizeof(NroHeader) == 0x80, "NroHeader has wrong size");
180
181} // namespace Service::RO
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index e2e399534..6808247a9 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -93,13 +93,13 @@ Result ServerManager::RegisterSession(Kernel::KServerSession* session,
93} 93}
94 94
95Result ServerManager::RegisterNamedService(const std::string& service_name, 95Result ServerManager::RegisterNamedService(const std::string& service_name,
96 std::shared_ptr<SessionRequestHandler>&& handler, 96 SessionRequestHandlerFactory&& handler_factory,
97 u32 max_sessions) { 97 u32 max_sessions) {
98 ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); 98 ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
99 99
100 // Add the new server to sm:. 100 // Add the new server to sm:.
101 ASSERT(R_SUCCEEDED( 101 ASSERT(R_SUCCEEDED(
102 m_system.ServiceManager().RegisterService(service_name, max_sessions, handler))); 102 m_system.ServiceManager().RegisterService(service_name, max_sessions, handler_factory)));
103 103
104 // Get the registered port. 104 // Get the registered port.
105 Kernel::KPort* port{}; 105 Kernel::KPort* port{};
@@ -112,7 +112,7 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
112 // Begin tracking the server port. 112 // Begin tracking the server port.
113 { 113 {
114 std::scoped_lock ll{m_list_mutex}; 114 std::scoped_lock ll{m_list_mutex};
115 m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler)); 115 m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory));
116 } 116 }
117 117
118 // Signal the wakeup event. 118 // Signal the wakeup event.
@@ -121,8 +121,18 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
121 R_SUCCEED(); 121 R_SUCCEED();
122} 122}
123 123
124Result ServerManager::RegisterNamedService(const std::string& service_name,
125 std::shared_ptr<SessionRequestHandler>&& handler,
126 u32 max_sessions) {
127 // Make the factory.
128 const auto HandlerFactory = [handler]() { return handler; };
129
130 // Register the service with the new factory.
131 R_RETURN(this->RegisterNamedService(service_name, std::move(HandlerFactory), max_sessions));
132}
133
124Result ServerManager::ManageNamedPort(const std::string& service_name, 134Result ServerManager::ManageNamedPort(const std::string& service_name,
125 std::shared_ptr<SessionRequestHandler>&& handler, 135 SessionRequestHandlerFactory&& handler_factory,
126 u32 max_sessions) { 136 u32 max_sessions) {
127 ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); 137 ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
128 138
@@ -149,7 +159,7 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,
149 // Begin tracking the server port. 159 // Begin tracking the server port.
150 { 160 {
151 std::scoped_lock ll{m_list_mutex}; 161 std::scoped_lock ll{m_list_mutex};
152 m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler)); 162 m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory));
153 } 163 }
154 164
155 // We succeeded. 165 // We succeeded.
@@ -269,13 +279,13 @@ Result ServerManager::WaitAndProcessImpl() {
269 case HandleType::Port: { 279 case HandleType::Port: {
270 // Port signaled. 280 // Port signaled.
271 auto* port = wait_obj->DynamicCast<Kernel::KServerPort*>(); 281 auto* port = wait_obj->DynamicCast<Kernel::KServerPort*>();
272 std::shared_ptr<SessionRequestHandler> handler; 282 SessionRequestHandlerFactory handler_factory;
273 283
274 // Remove from tracking. 284 // Remove from tracking.
275 { 285 {
276 std::scoped_lock ll{m_list_mutex}; 286 std::scoped_lock ll{m_list_mutex};
277 ASSERT(m_ports.contains(port)); 287 ASSERT(m_ports.contains(port));
278 m_ports.at(port).swap(handler); 288 m_ports.at(port).swap(handler_factory);
279 m_ports.erase(port); 289 m_ports.erase(port);
280 } 290 }
281 291
@@ -283,7 +293,7 @@ Result ServerManager::WaitAndProcessImpl() {
283 sl.unlock(); 293 sl.unlock();
284 294
285 // Finish. 295 // Finish.
286 R_RETURN(this->OnPortEvent(port, std::move(handler))); 296 R_RETURN(this->OnPortEvent(port, std::move(handler_factory)));
287 } 297 }
288 case HandleType::Session: { 298 case HandleType::Session: {
289 // Session signaled. 299 // Session signaled.
@@ -333,19 +343,19 @@ Result ServerManager::WaitAndProcessImpl() {
333} 343}
334 344
335Result ServerManager::OnPortEvent(Kernel::KServerPort* port, 345Result ServerManager::OnPortEvent(Kernel::KServerPort* port,
336 std::shared_ptr<SessionRequestHandler>&& handler) { 346 SessionRequestHandlerFactory&& handler_factory) {
337 // Accept a new server session. 347 // Accept a new server session.
338 Kernel::KServerSession* session = port->AcceptSession(); 348 Kernel::KServerSession* session = port->AcceptSession();
339 ASSERT(session != nullptr); 349 ASSERT(session != nullptr);
340 350
341 // Create the session manager and install the handler. 351 // Create the session manager and install the handler.
342 auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this); 352 auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this);
343 manager->SetSessionHandler(std::shared_ptr(handler)); 353 manager->SetSessionHandler(handler_factory());
344 354
345 // Track the server session. 355 // Track the server session.
346 { 356 {
347 std::scoped_lock ll{m_list_mutex}; 357 std::scoped_lock ll{m_list_mutex};
348 m_ports.emplace(port, std::move(handler)); 358 m_ports.emplace(port, std::move(handler_factory));
349 m_sessions.emplace(session, std::move(manager)); 359 m_sessions.emplace(session, std::move(manager));
350 } 360 }
351 361
diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h
index 58b0a0832..c4bc07262 100644
--- a/src/core/hle/service/server_manager.h
+++ b/src/core/hle/service/server_manager.h
@@ -13,6 +13,7 @@
13#include "common/polyfill_thread.h" 13#include "common/polyfill_thread.h"
14#include "common/thread.h" 14#include "common/thread.h"
15#include "core/hle/result.h" 15#include "core/hle/result.h"
16#include "core/hle/service/hle_ipc.h"
16#include "core/hle/service/mutex.h" 17#include "core/hle/service/mutex.h"
17 18
18namespace Core { 19namespace Core {
@@ -28,10 +29,6 @@ class KSynchronizationObject;
28 29
29namespace Service { 30namespace Service {
30 31
31class HLERequestContext;
32class SessionRequestHandler;
33class SessionRequestManager;
34
35class ServerManager { 32class ServerManager {
36public: 33public:
37 explicit ServerManager(Core::System& system); 34 explicit ServerManager(Core::System& system);
@@ -40,10 +37,13 @@ public:
40 Result RegisterSession(Kernel::KServerSession* session, 37 Result RegisterSession(Kernel::KServerSession* session,
41 std::shared_ptr<SessionRequestManager> manager); 38 std::shared_ptr<SessionRequestManager> manager);
42 Result RegisterNamedService(const std::string& service_name, 39 Result RegisterNamedService(const std::string& service_name,
40 SessionRequestHandlerFactory&& handler_factory,
41 u32 max_sessions = 64);
42 Result RegisterNamedService(const std::string& service_name,
43 std::shared_ptr<SessionRequestHandler>&& handler, 43 std::shared_ptr<SessionRequestHandler>&& handler,
44 u32 max_sessions = 64); 44 u32 max_sessions = 64);
45 Result ManageNamedPort(const std::string& service_name, 45 Result ManageNamedPort(const std::string& service_name,
46 std::shared_ptr<SessionRequestHandler>&& handler, u32 max_sessions = 64); 46 SessionRequestHandlerFactory&& handler_factory, u32 max_sessions = 64);
47 Result ManageDeferral(Kernel::KEvent** out_event); 47 Result ManageDeferral(Kernel::KEvent** out_event);
48 48
49 Result LoopProcess(); 49 Result LoopProcess();
@@ -56,7 +56,7 @@ private:
56 56
57 Result LoopProcessImpl(); 57 Result LoopProcessImpl();
58 Result WaitAndProcessImpl(); 58 Result WaitAndProcessImpl();
59 Result OnPortEvent(Kernel::KServerPort* port, std::shared_ptr<SessionRequestHandler>&& handler); 59 Result OnPortEvent(Kernel::KServerPort* port, SessionRequestHandlerFactory&& handler_factory);
60 Result OnSessionEvent(Kernel::KServerSession* session, 60 Result OnSessionEvent(Kernel::KServerSession* session,
61 std::shared_ptr<SessionRequestManager>&& manager); 61 std::shared_ptr<SessionRequestManager>&& manager);
62 Result OnDeferralEvent(std::list<RequestState>&& deferrals); 62 Result OnDeferralEvent(std::list<RequestState>&& deferrals);
@@ -68,7 +68,7 @@ private:
68 std::mutex m_list_mutex; 68 std::mutex m_list_mutex;
69 69
70 // Guest state tracking 70 // Guest state tracking
71 std::map<Kernel::KServerPort*, std::shared_ptr<SessionRequestHandler>> m_ports{}; 71 std::map<Kernel::KServerPort*, SessionRequestHandlerFactory> m_ports{};
72 std::map<Kernel::KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{}; 72 std::map<Kernel::KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{};
73 Kernel::KEvent* m_event{}; 73 Kernel::KEvent* m_event{};
74 Kernel::KEvent* m_deferral_event{}; 74 Kernel::KEvent* m_deferral_event{};
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 0ad607391..00531b021 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -59,6 +59,7 @@
59#include "core/hle/service/prepo/prepo.h" 59#include "core/hle/service/prepo/prepo.h"
60#include "core/hle/service/psc/psc.h" 60#include "core/hle/service/psc/psc.h"
61#include "core/hle/service/ptm/ptm.h" 61#include "core/hle/service/ptm/ptm.h"
62#include "core/hle/service/ro/ro.h"
62#include "core/hle/service/service.h" 63#include "core/hle/service/service.h"
63#include "core/hle/service/set/settings.h" 64#include "core/hle/service/set/settings.h"
64#include "core/hle/service/sm/sm.h" 65#include "core/hle/service/sm/sm.h"
@@ -270,6 +271,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
270 kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); }); 271 kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
271 kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); }); 272 kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
272 kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); }); 273 kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); });
274 kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); });
273 kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); }); 275 kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
274 kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); }); 276 kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); });
275 kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); }); 277 kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); });
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 9ab718e0a..296ee6e89 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -51,7 +51,7 @@ static Result ValidateServiceName(const std::string& name) {
51} 51}
52 52
53Result ServiceManager::RegisterService(std::string name, u32 max_sessions, 53Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
54 SessionRequestHandlerPtr handler) { 54 SessionRequestHandlerFactory handler) {
55 R_TRY(ValidateServiceName(name)); 55 R_TRY(ValidateServiceName(name));
56 56
57 std::scoped_lock lk{lock}; 57 std::scoped_lock lk{lock};
@@ -121,7 +121,7 @@ void SM::Initialize(HLERequestContext& ctx) {
121 rb.Push(ResultSuccess); 121 rb.Push(ResultSuccess);
122} 122}
123 123
124void SM::GetService(HLERequestContext& ctx) { 124void SM::GetServiceCmif(HLERequestContext& ctx) {
125 Kernel::KClientSession* client_session{}; 125 Kernel::KClientSession* client_session{};
126 auto result = GetServiceImpl(&client_session, ctx); 126 auto result = GetServiceImpl(&client_session, ctx);
127 if (ctx.GetIsDeferred()) { 127 if (ctx.GetIsDeferred()) {
@@ -192,19 +192,32 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques
192 return result; 192 return result;
193 } 193 }
194 194
195 LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
196
197 *out_client_session = session; 195 *out_client_session = session;
198 return ResultSuccess; 196 return ResultSuccess;
199} 197}
200 198
201void SM::RegisterService(HLERequestContext& ctx) { 199void SM::RegisterServiceCmif(HLERequestContext& ctx) {
202 IPC::RequestParser rp{ctx}; 200 IPC::RequestParser rp{ctx};
203 std::string name(PopServiceName(rp)); 201 std::string name(PopServiceName(rp));
204 202
205 const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); 203 const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
206 const auto max_session_count = rp.PopRaw<u32>(); 204 const auto max_session_count = rp.PopRaw<u32>();
207 205
206 this->RegisterServiceImpl(ctx, name, max_session_count, is_light);
207}
208
209void SM::RegisterServiceTipc(HLERequestContext& ctx) {
210 IPC::RequestParser rp{ctx};
211 std::string name(PopServiceName(rp));
212
213 const auto max_session_count = rp.PopRaw<u32>();
214 const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
215
216 this->RegisterServiceImpl(ctx, name, max_session_count, is_light);
217}
218
219void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count,
220 bool is_light) {
208 LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, 221 LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
209 max_session_count, is_light); 222 max_session_count, is_light);
210 223
@@ -240,15 +253,15 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
240 service_manager{service_manager_}, kernel{system_.Kernel()} { 253 service_manager{service_manager_}, kernel{system_.Kernel()} {
241 RegisterHandlers({ 254 RegisterHandlers({
242 {0, &SM::Initialize, "Initialize"}, 255 {0, &SM::Initialize, "Initialize"},
243 {1, &SM::GetService, "GetService"}, 256 {1, &SM::GetServiceCmif, "GetService"},
244 {2, &SM::RegisterService, "RegisterService"}, 257 {2, &SM::RegisterServiceCmif, "RegisterService"},
245 {3, &SM::UnregisterService, "UnregisterService"}, 258 {3, &SM::UnregisterService, "UnregisterService"},
246 {4, nullptr, "DetachClient"}, 259 {4, nullptr, "DetachClient"},
247 }); 260 });
248 RegisterHandlersTipc({ 261 RegisterHandlersTipc({
249 {0, &SM::Initialize, "Initialize"}, 262 {0, &SM::Initialize, "Initialize"},
250 {1, &SM::GetServiceTipc, "GetService"}, 263 {1, &SM::GetServiceTipc, "GetService"},
251 {2, &SM::RegisterService, "RegisterService"}, 264 {2, &SM::RegisterServiceTipc, "RegisterService"},
252 {3, &SM::UnregisterService, "UnregisterService"}, 265 {3, &SM::UnregisterService, "UnregisterService"},
253 {4, nullptr, "DetachClient"}, 266 {4, nullptr, "DetachClient"},
254 }); 267 });
@@ -264,7 +277,9 @@ void LoopProcess(Core::System& system) {
264 server_manager->ManageDeferral(&deferral_event); 277 server_manager->ManageDeferral(&deferral_event);
265 service_manager.SetDeferralEvent(deferral_event); 278 service_manager.SetDeferralEvent(deferral_event);
266 279
267 server_manager->ManageNamedPort("sm:", std::make_shared<SM>(system.ServiceManager(), system)); 280 auto sm_service = std::make_shared<SM>(system.ServiceManager(), system);
281 server_manager->ManageNamedPort("sm:", [sm_service] { return sm_service; });
282
268 ServerManager::RunServer(std::move(server_manager)); 283 ServerManager::RunServer(std::move(server_manager));
269} 284}
270 285
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 14bfaf8c2..ff74f588a 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -37,12 +37,15 @@ public:
37 37
38private: 38private:
39 void Initialize(HLERequestContext& ctx); 39 void Initialize(HLERequestContext& ctx);
40 void GetService(HLERequestContext& ctx); 40 void GetServiceCmif(HLERequestContext& ctx);
41 void GetServiceTipc(HLERequestContext& ctx); 41 void GetServiceTipc(HLERequestContext& ctx);
42 void RegisterService(HLERequestContext& ctx); 42 void RegisterServiceCmif(HLERequestContext& ctx);
43 void RegisterServiceTipc(HLERequestContext& ctx);
43 void UnregisterService(HLERequestContext& ctx); 44 void UnregisterService(HLERequestContext& ctx);
44 45
45 Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx); 46 Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx);
47 void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count,
48 bool is_light);
46 49
47 ServiceManager& service_manager; 50 ServiceManager& service_manager;
48 Kernel::KernelCore& kernel; 51 Kernel::KernelCore& kernel;
@@ -53,7 +56,8 @@ public:
53 explicit ServiceManager(Kernel::KernelCore& kernel_); 56 explicit ServiceManager(Kernel::KernelCore& kernel_);
54 ~ServiceManager(); 57 ~ServiceManager();
55 58
56 Result RegisterService(std::string name, u32 max_sessions, SessionRequestHandlerPtr handler); 59 Result RegisterService(std::string name, u32 max_sessions,
60 SessionRequestHandlerFactory handler_factory);
57 Result UnregisterService(const std::string& name); 61 Result UnregisterService(const std::string& name);
58 Result GetServicePort(Kernel::KPort** out_port, const std::string& name); 62 Result GetServicePort(Kernel::KPort** out_port, const std::string& name);
59 63
@@ -64,7 +68,7 @@ public:
64 LOG_DEBUG(Service, "Can't find service: {}", service_name); 68 LOG_DEBUG(Service, "Can't find service: {}", service_name);
65 return nullptr; 69 return nullptr;
66 } 70 }
67 return std::static_pointer_cast<T>(service->second); 71 return std::static_pointer_cast<T>(service->second());
68 } 72 }
69 73
70 void InvokeControlRequest(HLERequestContext& context); 74 void InvokeControlRequest(HLERequestContext& context);
@@ -79,7 +83,7 @@ private:
79 83
80 /// Map of registered services, retrieved using GetServicePort. 84 /// Map of registered services, retrieved using GetServicePort.
81 std::mutex lock; 85 std::mutex lock;
82 std::unordered_map<std::string, SessionRequestHandlerPtr> registered_services; 86 std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services;
83 std::unordered_map<std::string, Kernel::KPort*> service_ports; 87 std::unordered_map<std::string, Kernel::KPort*> service_ports;
84 88
85 /// Kernel context 89 /// Kernel context
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 6c8427b0d..0fbb43057 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -240,7 +240,7 @@ private:
240 return ret; 240 return ret;
241 } 241 }
242 242
243 Result ReadImpl(std::vector<u8>* out_data, size_t size) { 243 Result ReadImpl(std::vector<u8>* out_data) {
244 ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; }); 244 ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
245 size_t actual_size{}; 245 size_t actual_size{};
246 Result res = backend->Read(&actual_size, *out_data); 246 Result res = backend->Read(&actual_size, *out_data);
@@ -326,8 +326,8 @@ private:
326 } 326 }
327 327
328 void Read(HLERequestContext& ctx) { 328 void Read(HLERequestContext& ctx) {
329 std::vector<u8> output_bytes; 329 std::vector<u8> output_bytes(ctx.GetWriteBufferSize());
330 const Result res = ReadImpl(&output_bytes, ctx.GetWriteBufferSize()); 330 const Result res = ReadImpl(&output_bytes);
331 IPC::ResponseBuilder rb{ctx, 3}; 331 IPC::ResponseBuilder rb{ctx, 3};
332 rb.Push(res); 332 rb.Push(res);
333 if (res == ResultSuccess) { 333 if (res == ResultSuccess) {
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 5b376b202..169bf4c8c 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -43,13 +43,9 @@ bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessA
43struct Memory::Impl { 43struct Memory::Impl {
44 explicit Impl(Core::System& system_) : system{system_} {} 44 explicit Impl(Core::System& system_) : system{system_} {}
45 45
46 void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { 46 void SetCurrentPageTable(Kernel::KProcess& process) {
47 current_page_table = &process.GetPageTable().GetImpl(); 47 current_page_table = &process.GetPageTable().GetImpl();
48 current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer(); 48 current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
49
50 const std::size_t address_space_width = process.GetPageTable().GetAddressSpaceWidth();
51
52 system.ArmInterface(core_id).PageTableChanged(*current_page_table, address_space_width);
53 } 49 }
54 50
55 void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, 51 void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
@@ -871,8 +867,8 @@ void Memory::Reset() {
871 impl = std::make_unique<Impl>(system); 867 impl = std::make_unique<Impl>(system);
872} 868}
873 869
874void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { 870void Memory::SetCurrentPageTable(Kernel::KProcess& process) {
875 impl->SetCurrentPageTable(process, core_id); 871 impl->SetCurrentPageTable(process);
876} 872}
877 873
878void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, 874void Memory::MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
diff --git a/src/core/memory.h b/src/core/memory.h
index ed8ebb5eb..c1879e78f 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -73,7 +73,7 @@ public:
73 * 73 *
74 * @param process The process to use the page table of. 74 * @param process The process to use the page table of.
75 */ 75 */
76 void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id); 76 void SetCurrentPageTable(Kernel::KProcess& process);
77 77
78 /** 78 /**
79 * Maps an allocated buffer onto a region of the emulated process address space. 79 * Maps an allocated buffer onto a region of the emulated process address space.
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index db30ba598..3fc4024dc 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -62,7 +62,7 @@ u64 StandardVmCallbacks::HidKeysDown() {
62 } 62 }
63 63
64 const auto applet_resource = hid->GetResourceManager(); 64 const auto applet_resource = hid->GetResourceManager();
65 if (applet_resource == nullptr) { 65 if (applet_resource == nullptr || applet_resource->GetNpad() == nullptr) {
66 LOG_WARNING(CheatEngine, 66 LOG_WARNING(CheatEngine,
67 "Attempted to read input state, but applet resource is not initialized!"); 67 "Attempted to read input state, but applet resource is not initialized!");
68 return 0; 68 return 0;
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 5d168cbc1..dc3883528 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -109,41 +109,11 @@ json GetProcessorStateData(const std::string& architecture, u64 entry_point, u64
109 return out; 109 return out;
110} 110}
111 111
112json GetProcessorStateDataAuto(Core::System& system) {
113 const auto* process{system.ApplicationProcess()};
114 auto& arm{system.CurrentArmInterface()};
115
116 Core::ARM_Interface::ThreadContext64 context{};
117 arm.SaveContext(context);
118
119 return GetProcessorStateData(process->Is64Bit() ? "AArch64" : "AArch32",
120 GetInteger(process->GetEntryPoint()), context.sp, context.pc,
121 context.pstate, context.cpu_registers);
122}
123
124json GetBacktraceData(Core::System& system) {
125 auto out = json::array();
126 const auto& backtrace{system.CurrentArmInterface().GetBacktrace()};
127 for (const auto& entry : backtrace) {
128 out.push_back({
129 {"module", entry.module},
130 {"address", fmt::format("{:016X}", entry.address)},
131 {"original_address", fmt::format("{:016X}", entry.original_address)},
132 {"offset", fmt::format("{:016X}", entry.offset)},
133 {"symbol_name", entry.name},
134 });
135 }
136
137 return out;
138}
139
140json GetFullDataAuto(const std::string& timestamp, u64 title_id, Core::System& system) { 112json GetFullDataAuto(const std::string& timestamp, u64 title_id, Core::System& system) {
141 json out; 113 json out;
142 114
143 out["yuzu_version"] = GetYuzuVersionData(); 115 out["yuzu_version"] = GetYuzuVersionData();
144 out["report_common"] = GetReportCommonData(title_id, ResultSuccess, timestamp); 116 out["report_common"] = GetReportCommonData(title_id, ResultSuccess, timestamp);
145 out["processor_state"] = GetProcessorStateDataAuto(system);
146 out["backtrace"] = GetBacktraceData(system);
147 117
148 return out; 118 return out;
149} 119}
@@ -351,8 +321,6 @@ void Reporter::SaveErrorReport(u64 title_id, Result result,
351 321
352 out["yuzu_version"] = GetYuzuVersionData(); 322 out["yuzu_version"] = GetYuzuVersionData();
353 out["report_common"] = GetReportCommonData(title_id, result, timestamp); 323 out["report_common"] = GetReportCommonData(title_id, result, timestamp);
354 out["processor_state"] = GetProcessorStateDataAuto(system);
355 out["backtrace"] = GetBacktraceData(system);
356 324
357 out["error_custom_text"] = { 325 out["error_custom_text"] = {
358 {"main", custom_text_main.value_or("")}, 326 {"main", custom_text_main.value_or("")},
diff --git a/src/tests/video_core/memory_tracker.cpp b/src/tests/video_core/memory_tracker.cpp
index 618793668..2dbff21af 100644
--- a/src/tests/video_core/memory_tracker.cpp
+++ b/src/tests/video_core/memory_tracker.cpp
@@ -23,13 +23,13 @@ constexpr VAddr c = 16 * HIGH_PAGE_SIZE;
23 23
24class RasterizerInterface { 24class RasterizerInterface {
25public: 25public:
26 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { 26 void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {
27 const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS}; 27 const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS};
28 const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >> 28 const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >>
29 Core::Memory::YUZU_PAGEBITS}; 29 Core::Memory::YUZU_PAGEBITS};
30 for (u64 page = page_start; page < page_end; ++page) { 30 for (u64 page = page_start; page < page_end; ++page) {
31 int& value = page_table[page]; 31 int& value = page_table[page];
32 value += delta; 32 value += (cache ? 1 : -1);
33 if (value < 0) { 33 if (value < 0) {
34 throw std::logic_error{"negative page"}; 34 throw std::logic_error{"negative page"};
35 } 35 }
@@ -546,4 +546,4 @@ TEST_CASE("MemoryTracker: Cached write downloads") {
546 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); 546 REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE));
547 memory_track->MarkRegionAsCpuModified(c, WORD); 547 memory_track->MarkRegionAsCpuModified(c, WORD);
548 REQUIRE(rasterizer.Count() == 0); 548 REQUIRE(rasterizer.Count() == 0);
549} \ No newline at end of file 549}
diff --git a/src/video_core/buffer_cache/word_manager.h b/src/video_core/buffer_cache/word_manager.h
index a336bde41..95b752055 100644
--- a/src/video_core/buffer_cache/word_manager.h
+++ b/src/video_core/buffer_cache/word_manager.h
@@ -473,7 +473,7 @@ private:
473 VAddr addr = cpu_addr + word_index * BYTES_PER_WORD; 473 VAddr addr = cpu_addr + word_index * BYTES_PER_WORD;
474 IteratePages(changed_bits, [&](size_t offset, size_t size) { 474 IteratePages(changed_bits, [&](size_t offset, size_t size) {
475 rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE, 475 rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE,
476 size * BYTES_PER_PAGE, add_to_rasterizer ? 1 : -1); 476 size * BYTES_PER_PAGE, add_to_rasterizer);
477 }); 477 });
478 } 478 }
479 479
diff --git a/src/video_core/host1x/ffmpeg/ffmpeg.cpp b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
index dcd07e6d2..96686da59 100644
--- a/src/video_core/host1x/ffmpeg/ffmpeg.cpp
+++ b/src/video_core/host1x/ffmpeg/ffmpeg.cpp
@@ -233,7 +233,12 @@ std::unique_ptr<Frame> DecoderContext::ReceiveFrame(bool* out_is_interlaced) {
233 return false; 233 return false;
234 } 234 }
235 235
236 *out_is_interlaced = frame->interlaced_frame != 0; 236 *out_is_interlaced =
237#if defined(FF_API_INTERLACED_FRAME) || LIBAVUTIL_VERSION_MAJOR >= 59
238 (frame->flags & AV_FRAME_FLAG_INTERLACED) != 0;
239#else
240 frame->interlaced_frame != 0;
241#endif
237 return true; 242 return true;
238 }; 243 };
239 244
diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp
index f200a650f..3c9477f6e 100644
--- a/src/video_core/rasterizer_accelerated.cpp
+++ b/src/video_core/rasterizer_accelerated.cpp
@@ -3,6 +3,7 @@
3 3
4#include <atomic> 4#include <atomic>
5 5
6#include "common/alignment.h"
6#include "common/assert.h" 7#include "common/assert.h"
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/div_ceil.h" 9#include "common/div_ceil.h"
@@ -11,61 +12,65 @@
11 12
12namespace VideoCore { 13namespace VideoCore {
13 14
15static constexpr u16 IdentityValue = 1;
16
14using namespace Core::Memory; 17using namespace Core::Memory;
15 18
16RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) 19RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) : map{}, cpu_memory{cpu_memory_} {
17 : cached_pages(std::make_unique<CachedPages>()), cpu_memory{cpu_memory_} {} 20 // We are tracking CPU memory, which cannot map more than 39 bits.
21 const VAddr start_address = 0;
22 const VAddr end_address = (1ULL << 39);
23 const IntervalType address_space_interval(start_address, end_address);
24 const auto value = std::make_pair(address_space_interval, IdentityValue);
25
26 map.add(value);
27}
18 28
19RasterizerAccelerated::~RasterizerAccelerated() = default; 29RasterizerAccelerated::~RasterizerAccelerated() = default;
20 30
21void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { 31void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {
22 u64 uncache_begin = 0; 32 std::scoped_lock lk{map_lock};
23 u64 cache_begin = 0;
24 u64 uncache_bytes = 0;
25 u64 cache_bytes = 0;
26
27 std::atomic_thread_fence(std::memory_order_acquire);
28 const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE);
29 for (u64 page = addr >> YUZU_PAGEBITS; page != page_end; ++page) {
30 std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page);
31
32 if (delta > 0) {
33 ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!");
34 } else if (delta < 0) {
35 ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!");
36 } else {
37 ASSERT_MSG(false, "Delta must be non-zero!");
38 }
39 33
40 // Adds or subtracts 1, as count is a unsigned 8-bit value 34 // Align sizes.
41 count.fetch_add(static_cast<u16>(delta), std::memory_order_release); 35 addr = Common::AlignDown(addr, YUZU_PAGESIZE);
42 36 size = Common::AlignUp(size, YUZU_PAGESIZE);
43 // Assume delta is either -1 or 1 37
44 if (count.load(std::memory_order::relaxed) == 0) { 38 // Declare the overall interval we are going to operate on.
45 if (uncache_bytes == 0) { 39 const VAddr start_address = addr;
46 uncache_begin = page; 40 const VAddr end_address = addr + size;
47 } 41 const IntervalType modification_range(start_address, end_address);
48 uncache_bytes += YUZU_PAGESIZE; 42
49 } else if (uncache_bytes > 0) { 43 // Find the boundaries of where to iterate.
50 cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, 44 const auto lower = map.lower_bound(modification_range);
51 false); 45 const auto upper = map.upper_bound(modification_range);
52 uncache_bytes = 0; 46
53 } 47 // Iterate over the contained intervals.
54 if (count.load(std::memory_order::relaxed) == 1 && delta > 0) { 48 for (auto it = lower; it != upper; it++) {
55 if (cache_bytes == 0) { 49 // Intersect interval range with modification range.
56 cache_begin = page; 50 const auto current_range = modification_range & it->first;
57 } 51
58 cache_bytes += YUZU_PAGESIZE; 52 // Calculate the address and size to operate over.
59 } else if (cache_bytes > 0) { 53 const auto current_addr = current_range.lower();
60 cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true); 54 const auto current_size = current_range.upper() - current_addr;
61 cache_bytes = 0; 55
56 // Get the current value of the range.
57 const auto value = it->second;
58
59 if (cache && value == IdentityValue) {
60 // If we are going to cache, and the value is not yet referenced, then cache this range.
61 cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, true);
62 } else if (!cache && value == IdentityValue + 1) {
63 // If we are going to uncache, and this is the last reference, then uncache this range.
64 cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, false);
62 } 65 }
63 } 66 }
64 if (uncache_bytes > 0) { 67
65 cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, false); 68 // Update the set.
66 } 69 const auto value = std::make_pair(modification_range, IdentityValue);
67 if (cache_bytes > 0) { 70 if (cache) {
68 cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true); 71 map.add(value);
72 } else {
73 map.subtract(value);
69 } 74 }
70} 75}
71 76
diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h
index e6c0ea87a..f1968f186 100644
--- a/src/video_core/rasterizer_accelerated.h
+++ b/src/video_core/rasterizer_accelerated.h
@@ -3,8 +3,8 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <array> 6#include <mutex>
7#include <atomic> 7#include <boost/icl/interval_map.hpp>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/rasterizer_interface.h" 10#include "video_core/rasterizer_interface.h"
@@ -21,28 +21,17 @@ public:
21 explicit RasterizerAccelerated(Core::Memory::Memory& cpu_memory_); 21 explicit RasterizerAccelerated(Core::Memory::Memory& cpu_memory_);
22 ~RasterizerAccelerated() override; 22 ~RasterizerAccelerated() override;
23 23
24 void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override; 24 void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) override;
25 25
26private: 26private:
27 class CacheEntry final { 27 using PageIndex = VAddr;
28 public: 28 using PageReferenceCount = u16;
29 CacheEntry() = default;
30 29
31 std::atomic_uint16_t& Count(std::size_t page) { 30 using IntervalMap = boost::icl::interval_map<PageIndex, PageReferenceCount>;
32 return values[page & 3]; 31 using IntervalType = IntervalMap::interval_type;
33 }
34 32
35 const std::atomic_uint16_t& Count(std::size_t page) const { 33 IntervalMap map;
36 return values[page & 3]; 34 std::mutex map_lock;
37 }
38
39 private:
40 std::array<std::atomic_uint16_t, 4> values{};
41 };
42 static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!");
43
44 using CachedPages = std::array<CacheEntry, 0x2000000>;
45 std::unique_ptr<CachedPages> cached_pages;
46 Core::Memory::Memory& cpu_memory; 35 Core::Memory::Memory& cpu_memory;
47}; 36};
48 37
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h
index af1469147..fd42d26b5 100644
--- a/src/video_core/rasterizer_interface.h
+++ b/src/video_core/rasterizer_interface.h
@@ -162,7 +162,7 @@ public:
162 } 162 }
163 163
164 /// Increase/decrease the number of object in pages touching the specified region 164 /// Increase/decrease the number of object in pages touching the specified region
165 virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {} 165 virtual void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {}
166 166
167 /// Initialize disk cached resources for the game being emulated 167 /// Initialize disk cached resources for the game being emulated
168 virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading, 168 virtual void LoadDiskResources(u64 title_id, std::stop_token stop_loading,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 9995b6dd4..279e5a4e0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -714,7 +714,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
714 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 714 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
715 715
716 std::scoped_lock lock{texture_cache.mutex}; 716 std::scoped_lock lock{texture_cache.mutex};
717 ImageView* const image_view{texture_cache.TryFindFramebufferImageView(framebuffer_addr)}; 717 ImageView* const image_view{
718 texture_cache.TryFindFramebufferImageView(config, framebuffer_addr)};
718 if (!image_view) { 719 if (!image_view) {
719 return false; 720 return false;
720 } 721 }
@@ -725,7 +726,6 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
725 screen_info.texture.width = image_view->size.width; 726 screen_info.texture.width = image_view->size.width;
726 screen_info.texture.height = image_view->size.height; 727 screen_info.texture.height = image_view->size.height;
727 screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D); 728 screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D);
728 screen_info.display_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format);
729 return true; 729 return true;
730} 730}
731 731
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 6bfed08a1..7a4f0c5c1 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -653,11 +653,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
653 }; 653 };
654 glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); 654 glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices));
655 655
656 if (screen_info.display_srgb) { 656 glDisable(GL_FRAMEBUFFER_SRGB);
657 glEnable(GL_FRAMEBUFFER_SRGB);
658 } else {
659 glDisable(GL_FRAMEBUFFER_SRGB);
660 }
661 glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), 657 glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width),
662 static_cast<GLfloat>(layout.height)); 658 static_cast<GLfloat>(layout.height));
663 659
@@ -710,8 +706,7 @@ void RendererOpenGL::RenderScreenshot() {
710 GLuint renderbuffer; 706 GLuint renderbuffer;
711 glGenRenderbuffers(1, &renderbuffer); 707 glGenRenderbuffers(1, &renderbuffer);
712 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); 708 glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
713 glRenderbufferStorage(GL_RENDERBUFFER, screen_info.display_srgb ? GL_SRGB8 : GL_RGB8, 709 glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height);
714 layout.width, layout.height);
715 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); 710 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
716 711
717 DrawScreen(layout); 712 DrawScreen(layout);
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index f1d5fd954..b70607635 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -53,7 +53,6 @@ struct TextureInfo {
53struct ScreenInfo { 53struct ScreenInfo {
54 GLuint display_texture{}; 54 GLuint display_texture{};
55 bool was_accelerated = false; 55 bool was_accelerated = false;
56 bool display_srgb{};
57 const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; 56 const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f};
58 TextureInfo texture; 57 TextureInfo texture;
59}; 58};
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index c4c30d807..100b70918 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -94,7 +94,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
94 device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), 94 device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(),
95 scheduler(device, state_tracker), 95 scheduler(device, state_tracker),
96 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, 96 swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
97 render_window.GetFramebufferLayout().height, false), 97 render_window.GetFramebufferLayout().height),
98 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, 98 present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
99 surface), 99 surface),
100 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager, 100 blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager,
@@ -131,11 +131,10 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
131 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; 131 const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
132 const bool use_accelerated = 132 const bool use_accelerated =
133 rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); 133 rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
134 const bool is_srgb = use_accelerated && screen_info.is_srgb;
135 RenderScreenshot(*framebuffer, use_accelerated); 134 RenderScreenshot(*framebuffer, use_accelerated);
136 135
137 Frame* frame = present_manager.GetRenderFrame(); 136 Frame* frame = present_manager.GetRenderFrame();
138 blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb); 137 blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated);
139 scheduler.Flush(*frame->render_ready); 138 scheduler.Flush(*frame->render_ready);
140 present_manager.Present(frame); 139 present_manager.Present(frame);
141 140
@@ -205,7 +204,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr
205 .flags = 0, 204 .flags = 0,
206 .image = *staging_image, 205 .image = *staging_image,
207 .viewType = VK_IMAGE_VIEW_TYPE_2D, 206 .viewType = VK_IMAGE_VIEW_TYPE_2D,
208 .format = screen_info.is_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM, 207 .format = VK_FORMAT_B8G8R8A8_UNORM,
209 .components{ 208 .components{
210 .r = VK_COMPONENT_SWIZZLE_IDENTITY, 209 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
211 .g = VK_COMPONENT_SWIZZLE_IDENTITY, 210 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index 5e461fbd0..60432f5ad 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -127,9 +127,9 @@ BlitScreen::BlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWin
127 Scheduler& scheduler_, const ScreenInfo& screen_info_) 127 Scheduler& scheduler_, const ScreenInfo& screen_info_)
128 : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_}, 128 : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_},
129 memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, 129 memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_},
130 scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_}, 130 scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} {
131 current_srgb{swapchain.IsSrgb()}, image_view_format{swapchain.GetImageViewFormat()} {
132 resource_ticks.resize(image_count); 131 resource_ticks.resize(image_count);
132 swapchain_view_format = swapchain.GetImageViewFormat();
133 133
134 CreateStaticResources(); 134 CreateStaticResources();
135 CreateDynamicResources(); 135 CreateDynamicResources();
@@ -480,28 +480,22 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer,
480} 480}
481 481
482void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, 482void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer,
483 bool use_accelerated, bool is_srgb) { 483 bool use_accelerated) {
484 // Recreate dynamic resources if the the image count or colorspace changed 484 // Recreate dynamic resources if the the image count or input format changed
485 const VkFormat current_framebuffer_format =
486 std::exchange(framebuffer_view_format, GetFormat(framebuffer));
485 if (const std::size_t swapchain_images = swapchain.GetImageCount(); 487 if (const std::size_t swapchain_images = swapchain.GetImageCount();
486 swapchain_images != image_count || current_srgb != is_srgb) { 488 swapchain_images != image_count || current_framebuffer_format != framebuffer_view_format) {
487 current_srgb = is_srgb;
488#ifdef ANDROID
489 // Android is already ordered the same as Switch.
490 image_view_format = current_srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
491#else
492 image_view_format = current_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM;
493#endif
494 image_count = swapchain_images; 489 image_count = swapchain_images;
495 Recreate(); 490 Recreate();
496 } 491 }
497 492
498 // Recreate the presentation frame if the dimensions of the window changed 493 // Recreate the presentation frame if the dimensions of the window changed
499 const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); 494 const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout();
500 if (layout.width != frame->width || layout.height != frame->height || 495 if (layout.width != frame->width || layout.height != frame->height) {
501 is_srgb != frame->is_srgb) {
502 Recreate(); 496 Recreate();
503 present_manager.RecreateFrame(frame, layout.width, layout.height, is_srgb, 497 present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format,
504 image_view_format, *renderpass); 498 *renderpass);
505 } 499 }
506 500
507 const VkExtent2D render_area{frame->width, frame->height}; 501 const VkExtent2D render_area{frame->width, frame->height};
@@ -629,7 +623,7 @@ void BlitScreen::CreateDescriptorPool() {
629} 623}
630 624
631void BlitScreen::CreateRenderPass() { 625void BlitScreen::CreateRenderPass() {
632 renderpass = CreateRenderPassImpl(image_view_format); 626 renderpass = CreateRenderPassImpl(swapchain_view_format);
633} 627}
634 628
635vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) { 629vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) {
@@ -1149,7 +1143,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1149 .pNext = nullptr, 1143 .pNext = nullptr,
1150 .flags = 0, 1144 .flags = 0,
1151 .imageType = VK_IMAGE_TYPE_2D, 1145 .imageType = VK_IMAGE_TYPE_2D,
1152 .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer), 1146 .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format,
1153 .extent = 1147 .extent =
1154 { 1148 {
1155 .width = (up_scale * framebuffer.width) >> down_shift, 1149 .width = (up_scale * framebuffer.width) >> down_shift,
@@ -1174,7 +1168,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) {
1174 .flags = 0, 1168 .flags = 0,
1175 .image = *image, 1169 .image = *image,
1176 .viewType = VK_IMAGE_VIEW_TYPE_2D, 1170 .viewType = VK_IMAGE_VIEW_TYPE_2D,
1177 .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer), 1171 .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format,
1178 .components = 1172 .components =
1179 { 1173 {
1180 .r = VK_COMPONENT_SWIZZLE_IDENTITY, 1174 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h
index 8365b5668..16b882b6d 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.h
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.h
@@ -52,7 +52,6 @@ struct ScreenInfo {
52 VkImageView image_view{}; 52 VkImageView image_view{};
53 u32 width{}; 53 u32 width{};
54 u32 height{}; 54 u32 height{};
55 bool is_srgb{};
56}; 55};
57 56
58class BlitScreen { 57class BlitScreen {
@@ -69,7 +68,7 @@ public:
69 const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated); 68 const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated);
70 69
71 void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, 70 void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer,
72 bool use_accelerated, bool is_srgb); 71 bool use_accelerated);
73 72
74 [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, 73 [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view,
75 VkExtent2D extent); 74 VkExtent2D extent);
@@ -161,8 +160,8 @@ private:
161 u32 raw_width = 0; 160 u32 raw_width = 0;
162 u32 raw_height = 0; 161 u32 raw_height = 0;
163 Service::android::PixelFormat pixel_format{}; 162 Service::android::PixelFormat pixel_format{};
164 bool current_srgb; 163 VkFormat framebuffer_view_format;
165 VkFormat image_view_format; 164 VkFormat swapchain_view_format;
166 165
167 std::unique_ptr<FSR> fsr; 166 std::unique_ptr<FSR> fsr;
168 std::unique_ptr<SMAA> smaa; 167 std::unique_ptr<SMAA> smaa;
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp
index 2ef36583b..8e4c74b5c 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.cpp
+++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp
@@ -172,13 +172,12 @@ void PresentManager::Present(Frame* frame) {
172 }); 172 });
173} 173}
174 174
175void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb, 175void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format,
176 VkFormat image_view_format, VkRenderPass rd) { 176 VkRenderPass rd) {
177 auto& dld = device.GetLogical(); 177 auto& dld = device.GetLogical();
178 178
179 frame->width = width; 179 frame->width = width;
180 frame->height = height; 180 frame->height = height;
181 frame->is_srgb = is_srgb;
182 181
183 frame->image = memory_allocator.CreateImage({ 182 frame->image = memory_allocator.CreateImage({
184 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 183 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
@@ -289,7 +288,7 @@ void PresentManager::PresentThread(std::stop_token token) {
289} 288}
290 289
291void PresentManager::RecreateSwapchain(Frame* frame) { 290void PresentManager::RecreateSwapchain(Frame* frame) {
292 swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb); 291 swapchain.Create(*surface, frame->width, frame->height);
293 image_count = swapchain.GetImageCount(); 292 image_count = swapchain.GetImageCount();
294} 293}
295 294
@@ -319,12 +318,12 @@ void PresentManager::CopyToSwapchain(Frame* frame) {
319void PresentManager::CopyToSwapchainImpl(Frame* frame) { 318void PresentManager::CopyToSwapchainImpl(Frame* frame) {
320 MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); 319 MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain);
321 320
322 // If the size or colorspace of the incoming frames has changed, recreate the swapchain 321 // If the size of the incoming frames has changed, recreate the swapchain
323 // to account for that. 322 // to account for that.
324 const bool srgb_changed = swapchain.NeedsRecreation(frame->is_srgb); 323 const bool is_suboptimal = swapchain.NeedsRecreation();
325 const bool size_changed = 324 const bool size_changed =
326 swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; 325 swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height;
327 if (srgb_changed || size_changed) { 326 if (is_suboptimal || size_changed) {
328 RecreateSwapchain(frame); 327 RecreateSwapchain(frame);
329 } 328 }
330 329
diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h
index a3d825fe6..337171a09 100644
--- a/src/video_core/renderer_vulkan/vk_present_manager.h
+++ b/src/video_core/renderer_vulkan/vk_present_manager.h
@@ -25,7 +25,6 @@ class Swapchain;
25struct Frame { 25struct Frame {
26 u32 width; 26 u32 width;
27 u32 height; 27 u32 height;
28 bool is_srgb;
29 vk::Image image; 28 vk::Image image;
30 vk::ImageView image_view; 29 vk::ImageView image_view;
31 vk::Framebuffer framebuffer; 30 vk::Framebuffer framebuffer;
@@ -48,8 +47,8 @@ public:
48 void Present(Frame* frame); 47 void Present(Frame* frame);
49 48
50 /// Recreates the present frame to match the provided parameters 49 /// Recreates the present frame to match the provided parameters
51 void RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb, 50 void RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format,
52 VkFormat image_view_format, VkRenderPass rd); 51 VkRenderPass rd);
53 52
54 /// Waits for the present thread to finish presenting all queued frames. 53 /// Waits for the present thread to finish presenting all queued frames.
55 void WaitPresent(); 54 void WaitPresent();
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index b6f52e017..59829c88b 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -783,7 +783,8 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
783 return false; 783 return false;
784 } 784 }
785 std::scoped_lock lock{texture_cache.mutex}; 785 std::scoped_lock lock{texture_cache.mutex};
786 ImageView* const image_view = texture_cache.TryFindFramebufferImageView(framebuffer_addr); 786 ImageView* const image_view =
787 texture_cache.TryFindFramebufferImageView(config, framebuffer_addr);
787 if (!image_view) { 788 if (!image_view) {
788 return false; 789 return false;
789 } 790 }
@@ -792,7 +793,6 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config,
792 screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D); 793 screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D);
793 screen_info.width = image_view->size.width; 794 screen_info.width = image_view->size.width;
794 screen_info.height = image_view->size.height; 795 screen_info.height = image_view->size.height;
795 screen_info.is_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format);
796 return true; 796 return true;
797} 797}
798 798
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index 821f44f1a..86a30dcd1 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -105,14 +105,14 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap
105} // Anonymous namespace 105} // Anonymous namespace
106 106
107Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, 107Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_,
108 u32 width_, u32 height_, bool srgb) 108 u32 width_, u32 height_)
109 : surface{surface_}, device{device_}, scheduler{scheduler_} { 109 : surface{surface_}, device{device_}, scheduler{scheduler_} {
110 Create(surface_, width_, height_, srgb); 110 Create(surface_, width_, height_);
111} 111}
112 112
113Swapchain::~Swapchain() = default; 113Swapchain::~Swapchain() = default;
114 114
115void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_, bool srgb) { 115void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_) {
116 is_outdated = false; 116 is_outdated = false;
117 is_suboptimal = false; 117 is_suboptimal = false;
118 width = width_; 118 width = width_;
@@ -127,7 +127,7 @@ void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_, bool srgb
127 127
128 Destroy(); 128 Destroy();
129 129
130 CreateSwapchain(capabilities, srgb); 130 CreateSwapchain(capabilities);
131 CreateSemaphores(); 131 CreateSemaphores();
132 132
133 resource_ticks.clear(); 133 resource_ticks.clear();
@@ -196,7 +196,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) {
196 } 196 }
197} 197}
198 198
199void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { 199void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
200 const auto physical_device{device.GetPhysical()}; 200 const auto physical_device{device.GetPhysical()};
201 const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; 201 const auto formats{physical_device.GetSurfaceFormatsKHR(surface)};
202 const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface); 202 const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface);
@@ -274,15 +274,14 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo
274 swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); 274 swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci);
275 275
276 extent = swapchain_ci.imageExtent; 276 extent = swapchain_ci.imageExtent;
277 current_srgb = srgb;
278 277
279 images = swapchain.GetImages(); 278 images = swapchain.GetImages();
280 image_count = static_cast<u32>(images.size()); 279 image_count = static_cast<u32>(images.size());
281#ifdef ANDROID 280#ifdef ANDROID
282 // Android is already ordered the same as Switch. 281 // Android is already ordered the same as Switch.
283 image_view_format = srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; 282 image_view_format = VK_FORMAT_R8G8B8A8_UNORM;
284#else 283#else
285 image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; 284 image_view_format = VK_FORMAT_B8G8R8A8_UNORM;
286#endif 285#endif
287} 286}
288 287
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h
index b8a1465a6..d264f06e4 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.h
+++ b/src/video_core/renderer_vulkan/vk_swapchain.h
@@ -20,11 +20,11 @@ class Scheduler;
20class Swapchain { 20class Swapchain {
21public: 21public:
22 explicit Swapchain(VkSurfaceKHR surface, const Device& device, Scheduler& scheduler, u32 width, 22 explicit Swapchain(VkSurfaceKHR surface, const Device& device, Scheduler& scheduler, u32 width,
23 u32 height, bool srgb); 23 u32 height);
24 ~Swapchain(); 24 ~Swapchain();
25 25
26 /// Creates (or recreates) the swapchain with a given size. 26 /// Creates (or recreates) the swapchain with a given size.
27 void Create(VkSurfaceKHR surface, u32 width, u32 height, bool srgb); 27 void Create(VkSurfaceKHR surface, u32 width, u32 height);
28 28
29 /// Acquires the next image in the swapchain, waits as needed. 29 /// Acquires the next image in the swapchain, waits as needed.
30 bool AcquireNextImage(); 30 bool AcquireNextImage();
@@ -33,13 +33,8 @@ public:
33 void Present(VkSemaphore render_semaphore); 33 void Present(VkSemaphore render_semaphore);
34 34
35 /// Returns true when the swapchain needs to be recreated. 35 /// Returns true when the swapchain needs to be recreated.
36 bool NeedsRecreation(bool is_srgb) const { 36 bool NeedsRecreation() const {
37 return HasColorSpaceChanged(is_srgb) || IsSubOptimal() || NeedsPresentModeUpdate(); 37 return IsSubOptimal() || NeedsPresentModeUpdate();
38 }
39
40 /// Returns true when the color space has changed.
41 bool HasColorSpaceChanged(bool is_srgb) const {
42 return current_srgb != is_srgb;
43 } 38 }
44 39
45 /// Returns true when the swapchain is outdated. 40 /// Returns true when the swapchain is outdated.
@@ -52,11 +47,6 @@ public:
52 return is_suboptimal; 47 return is_suboptimal;
53 } 48 }
54 49
55 /// Returns true when the swapchain format is in the srgb color space
56 bool IsSrgb() const {
57 return current_srgb;
58 }
59
60 VkExtent2D GetSize() const { 50 VkExtent2D GetSize() const {
61 return extent; 51 return extent;
62 } 52 }
@@ -110,7 +100,7 @@ public:
110 } 100 }
111 101
112private: 102private:
113 void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb); 103 void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities);
114 void CreateSemaphores(); 104 void CreateSemaphores();
115 void CreateImageViews(); 105 void CreateImageViews();
116 106
@@ -144,7 +134,6 @@ private:
144 bool has_mailbox{false}; 134 bool has_mailbox{false};
145 bool has_fifo_relaxed{false}; 135 bool has_fifo_relaxed{false};
146 136
147 bool current_srgb{};
148 bool is_outdated{}; 137 bool is_outdated{};
149 bool is_suboptimal{}; 138 bool is_suboptimal{};
150}; 139};
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp
index e81cd031b..a109f9cbe 100644
--- a/src/video_core/shader_cache.cpp
+++ b/src/video_core/shader_cache.cpp
@@ -132,7 +132,7 @@ void ShaderCache::Register(std::unique_ptr<ShaderInfo> data, VAddr addr, size_t
132 132
133 storage.push_back(std::move(data)); 133 storage.push_back(std::move(data));
134 134
135 rasterizer.UpdatePagesCachedCount(addr, size, 1); 135 rasterizer.UpdatePagesCachedCount(addr, size, true);
136} 136}
137 137
138void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) { 138void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) {
@@ -209,7 +209,7 @@ void ShaderCache::UnmarkMemory(Entry* entry) {
209 209
210 const VAddr addr = entry->addr_start; 210 const VAddr addr = entry->addr_start;
211 const size_t size = entry->addr_end - addr; 211 const size_t size = entry->addr_end - addr;
212 rasterizer.UpdatePagesCachedCount(addr, size, -1); 212 rasterizer.UpdatePagesCachedCount(addr, size, false);
213} 213}
214 214
215void ShaderCache::RemoveShadersFromStorage(std::span<ShaderInfo*> removed_shaders) { 215void ShaderCache::RemoveShadersFromStorage(std::span<ShaderInfo*> removed_shaders) {
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index dade38b18..d7941f6a4 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -712,14 +712,15 @@ bool TextureCache<P>::BlitImage(const Tegra::Engines::Fermi2D::Surface& dst,
712} 712}
713 713
714template <class P> 714template <class P>
715typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_addr) { 715typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(
716 const Tegra::FramebufferConfig& config, VAddr cpu_addr) {
716 // TODO: Properly implement this 717 // TODO: Properly implement this
717 const auto it = page_table.find(cpu_addr >> YUZU_PAGEBITS); 718 const auto it = page_table.find(cpu_addr >> YUZU_PAGEBITS);
718 if (it == page_table.end()) { 719 if (it == page_table.end()) {
719 return nullptr; 720 return nullptr;
720 } 721 }
721 const auto& image_map_ids = it->second; 722 const auto& image_map_ids = it->second;
722 boost::container::small_vector<const ImageBase*, 4> valid_images; 723 boost::container::small_vector<ImageId, 4> valid_image_ids;
723 for (const ImageMapId map_id : image_map_ids) { 724 for (const ImageMapId map_id : image_map_ids) {
724 const ImageMapView& map = slot_map_views[map_id]; 725 const ImageMapView& map = slot_map_views[map_id];
725 const ImageBase& image = slot_images[map.image_id]; 726 const ImageBase& image = slot_images[map.image_id];
@@ -729,18 +730,34 @@ typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_ad
729 if (image.image_view_ids.empty()) { 730 if (image.image_view_ids.empty()) {
730 continue; 731 continue;
731 } 732 }
732 valid_images.push_back(&image); 733 valid_image_ids.push_back(map.image_id);
733 } 734 }
734 735
735 if (valid_images.size() == 1) [[likely]] { 736 const auto view_format = [&]() {
736 return &slot_image_views[valid_images[0]->image_view_ids.at(0)]; 737 switch (config.pixel_format) {
738 case Service::android::PixelFormat::Rgb565:
739 return PixelFormat::R5G6B5_UNORM;
740 case Service::android::PixelFormat::Bgra8888:
741 return PixelFormat::B8G8R8A8_UNORM;
742 default:
743 return PixelFormat::A8B8G8R8_UNORM;
744 }
745 }();
746
747 const auto GetImageViewForFramebuffer = [&](ImageId image_id) {
748 const ImageViewInfo info{ImageViewType::e2D, view_format};
749 return &slot_image_views[FindOrEmplaceImageView(image_id, info)];
750 };
751
752 if (valid_image_ids.size() == 1) [[likely]] {
753 return GetImageViewForFramebuffer(valid_image_ids.front());
737 } 754 }
738 755
739 if (valid_images.size() > 0) [[unlikely]] { 756 if (valid_image_ids.size() > 0) [[unlikely]] {
740 std::ranges::sort(valid_images, [](const auto* a, const auto* b) { 757 auto most_recent = std::ranges::max_element(valid_image_ids, [&](auto a, auto b) {
741 return a->modification_tick > b->modification_tick; 758 return slot_images[a].modification_tick < slot_images[b].modification_tick;
742 }); 759 });
743 return &slot_image_views[valid_images[0]->image_view_ids.at(0)]; 760 return GetImageViewForFramebuffer(*most_recent);
744 } 761 }
745 762
746 return nullptr; 763 return nullptr;
@@ -2063,7 +2080,7 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
2063 ASSERT(False(image.flags & ImageFlagBits::Tracked)); 2080 ASSERT(False(image.flags & ImageFlagBits::Tracked));
2064 image.flags |= ImageFlagBits::Tracked; 2081 image.flags |= ImageFlagBits::Tracked;
2065 if (False(image.flags & ImageFlagBits::Sparse)) { 2082 if (False(image.flags & ImageFlagBits::Sparse)) {
2066 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1); 2083 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, true);
2067 return; 2084 return;
2068 } 2085 }
2069 if (True(image.flags & ImageFlagBits::Registered)) { 2086 if (True(image.flags & ImageFlagBits::Registered)) {
@@ -2074,13 +2091,13 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) {
2074 const auto& map = slot_map_views[map_view_id]; 2091 const auto& map = slot_map_views[map_view_id];
2075 const VAddr cpu_addr = map.cpu_addr; 2092 const VAddr cpu_addr = map.cpu_addr;
2076 const std::size_t size = map.size; 2093 const std::size_t size = map.size;
2077 rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); 2094 rasterizer.UpdatePagesCachedCount(cpu_addr, size, true);
2078 } 2095 }
2079 return; 2096 return;
2080 } 2097 }
2081 ForEachSparseSegment(image, 2098 ForEachSparseSegment(image,
2082 [this]([[maybe_unused]] GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { 2099 [this]([[maybe_unused]] GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) {
2083 rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); 2100 rasterizer.UpdatePagesCachedCount(cpu_addr, size, true);
2084 }); 2101 });
2085} 2102}
2086 2103
@@ -2089,7 +2106,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
2089 ASSERT(True(image.flags & ImageFlagBits::Tracked)); 2106 ASSERT(True(image.flags & ImageFlagBits::Tracked));
2090 image.flags &= ~ImageFlagBits::Tracked; 2107 image.flags &= ~ImageFlagBits::Tracked;
2091 if (False(image.flags & ImageFlagBits::Sparse)) { 2108 if (False(image.flags & ImageFlagBits::Sparse)) {
2092 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1); 2109 rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, false);
2093 return; 2110 return;
2094 } 2111 }
2095 ASSERT(True(image.flags & ImageFlagBits::Registered)); 2112 ASSERT(True(image.flags & ImageFlagBits::Registered));
@@ -2100,7 +2117,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) {
2100 const auto& map = slot_map_views[map_view_id]; 2117 const auto& map = slot_map_views[map_view_id];
2101 const VAddr cpu_addr = map.cpu_addr; 2118 const VAddr cpu_addr = map.cpu_addr;
2102 const std::size_t size = map.size; 2119 const std::size_t size = map.size;
2103 rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1); 2120 rasterizer.UpdatePagesCachedCount(cpu_addr, size, false);
2104 } 2121 }
2105} 2122}
2106 2123
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index a40825c9f..cbe56e166 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -209,7 +209,8 @@ public:
209 const Tegra::Engines::Fermi2D::Config& copy); 209 const Tegra::Engines::Fermi2D::Config& copy);
210 210
211 /// Try to find a cached image view in the given CPU address 211 /// Try to find a cached image view in the given CPU address
212 [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr); 212 [[nodiscard]] ImageView* TryFindFramebufferImageView(const Tegra::FramebufferConfig& config,
213 VAddr cpu_addr);
213 214
214 /// Return true when there are uncommitted images to be downloaded 215 /// Return true when there are uncommitted images to be downloaded
215 [[nodiscard]] bool HasUncommittedFlushes() const noexcept; 216 [[nodiscard]] bool HasUncommittedFlushes() const noexcept;
diff --git a/src/yuzu/applets/qt_profile_select.cpp b/src/yuzu/applets/qt_profile_select.cpp
index 1f3f23038..79162a491 100644
--- a/src/yuzu/applets/qt_profile_select.cpp
+++ b/src/yuzu/applets/qt_profile_select.cpp
@@ -14,6 +14,8 @@
14#include "common/fs/path_util.h" 14#include "common/fs/path_util.h"
15#include "common/string_util.h" 15#include "common/string_util.h"
16#include "core/constants.h" 16#include "core/constants.h"
17#include "core/core.h"
18#include "core/hle/service/acc/profile_manager.h"
17#include "yuzu/applets/qt_profile_select.h" 19#include "yuzu/applets/qt_profile_select.h"
18#include "yuzu/main.h" 20#include "yuzu/main.h"
19#include "yuzu/util/controller_navigation.h" 21#include "yuzu/util/controller_navigation.h"
@@ -47,9 +49,9 @@ QPixmap GetIcon(Common::UUID uuid) {
47} // Anonymous namespace 49} // Anonymous namespace
48 50
49QtProfileSelectionDialog::QtProfileSelectionDialog( 51QtProfileSelectionDialog::QtProfileSelectionDialog(
50 Core::HID::HIDCore& hid_core, QWidget* parent, 52 Core::System& system, QWidget* parent,
51 const Core::Frontend::ProfileSelectParameters& parameters) 53 const Core::Frontend::ProfileSelectParameters& parameters)
52 : QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) { 54 : QDialog(parent), profile_manager{system.GetProfileManager()} {
53 outer_layout = new QVBoxLayout; 55 outer_layout = new QVBoxLayout;
54 56
55 instruction_label = new QLabel(); 57 instruction_label = new QLabel();
@@ -68,7 +70,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(
68 tree_view = new QTreeView; 70 tree_view = new QTreeView;
69 item_model = new QStandardItemModel(tree_view); 71 item_model = new QStandardItemModel(tree_view);
70 tree_view->setModel(item_model); 72 tree_view->setModel(item_model);
71 controller_navigation = new ControllerNavigation(hid_core, this); 73 controller_navigation = new ControllerNavigation(system.HIDCore(), this);
72 74
73 tree_view->setAlternatingRowColors(true); 75 tree_view->setAlternatingRowColors(true);
74 tree_view->setSelectionMode(QHeaderView::SingleSelection); 76 tree_view->setSelectionMode(QHeaderView::SingleSelection);
@@ -106,10 +108,10 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(
106 SelectUser(tree_view->currentIndex()); 108 SelectUser(tree_view->currentIndex());
107 }); 109 });
108 110
109 const auto& profiles = profile_manager->GetAllUsers(); 111 const auto& profiles = profile_manager.GetAllUsers();
110 for (const auto& user : profiles) { 112 for (const auto& user : profiles) {
111 Service::Account::ProfileBase profile{}; 113 Service::Account::ProfileBase profile{};
112 if (!profile_manager->GetProfileBase(user, profile)) 114 if (!profile_manager.GetProfileBase(user, profile))
113 continue; 115 continue;
114 116
115 const auto username = Common::StringFromFixedZeroTerminatedBuffer( 117 const auto username = Common::StringFromFixedZeroTerminatedBuffer(
@@ -134,7 +136,7 @@ QtProfileSelectionDialog::~QtProfileSelectionDialog() {
134 136
135int QtProfileSelectionDialog::exec() { 137int QtProfileSelectionDialog::exec() {
136 // Skip profile selection when there's only one. 138 // Skip profile selection when there's only one.
137 if (profile_manager->GetUserCount() == 1) { 139 if (profile_manager.GetUserCount() == 1) {
138 user_index = 0; 140 user_index = 0;
139 return QDialog::Accepted; 141 return QDialog::Accepted;
140 } 142 }
diff --git a/src/yuzu/applets/qt_profile_select.h b/src/yuzu/applets/qt_profile_select.h
index 99056e274..607f1777c 100644
--- a/src/yuzu/applets/qt_profile_select.h
+++ b/src/yuzu/applets/qt_profile_select.h
@@ -7,7 +7,6 @@
7#include <QDialog> 7#include <QDialog>
8#include <QList> 8#include <QList>
9#include "core/frontend/applets/profile_select.h" 9#include "core/frontend/applets/profile_select.h"
10#include "core/hle/service/acc/profile_manager.h"
11 10
12class ControllerNavigation; 11class ControllerNavigation;
13class GMainWindow; 12class GMainWindow;
@@ -20,15 +19,19 @@ class QStandardItemModel;
20class QTreeView; 19class QTreeView;
21class QVBoxLayout; 20class QVBoxLayout;
22 21
23namespace Core::HID { 22namespace Core {
24class HIDCore; 23class System;
25} // namespace Core::HID 24}
25
26namespace Service::Account {
27class ProfileManager;
28}
26 29
27class QtProfileSelectionDialog final : public QDialog { 30class QtProfileSelectionDialog final : public QDialog {
28 Q_OBJECT 31 Q_OBJECT
29 32
30public: 33public:
31 explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent, 34 explicit QtProfileSelectionDialog(Core::System& system, QWidget* parent,
32 const Core::Frontend::ProfileSelectParameters& parameters); 35 const Core::Frontend::ProfileSelectParameters& parameters);
33 ~QtProfileSelectionDialog() override; 36 ~QtProfileSelectionDialog() override;
34 37
@@ -58,7 +61,7 @@ private:
58 QScrollArea* scroll_area; 61 QScrollArea* scroll_area;
59 QDialogButtonBox* buttons; 62 QDialogButtonBox* buttons;
60 63
61 std::unique_ptr<Service::Account::ProfileManager> profile_manager; 64 Service::Account::ProfileManager& profile_manager;
62 ControllerNavigation* controller_navigation = nullptr; 65 ControllerNavigation* controller_navigation = nullptr;
63}; 66};
64 67
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 22b51f39c..d842b0135 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -381,7 +381,7 @@
381 <item row="5" column="0"> 381 <item row="5" column="0">
382 <widget class="QCheckBox" name="disable_buffer_reorder"> 382 <widget class="QCheckBox" name="disable_buffer_reorder">
383 <property name="toolTip"> 383 <property name="toolTip">
384 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When checked, disables reording of mapped memory uploads which allows to associate uploads with specific draws. May reduce performance in some cases.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> 384 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When checked, disables reordering of mapped memory uploads which allows to associate uploads with specific draws. May reduce performance in some cases.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
385 </property> 385 </property>
386 <property name="text"> 386 <property name="text">
387 <string>Disable Buffer Reorder</string> 387 <string>Disable Buffer Reorder</string>
diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp
index 6d2219bf5..fa5f383d6 100644
--- a/src/yuzu/configuration/configure_profile_manager.cpp
+++ b/src/yuzu/configuration/configure_profile_manager.cpp
@@ -76,9 +76,9 @@ QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_t
76} 76}
77} // Anonymous namespace 77} // Anonymous namespace
78 78
79ConfigureProfileManager::ConfigureProfileManager(const Core::System& system_, QWidget* parent) 79ConfigureProfileManager::ConfigureProfileManager(Core::System& system_, QWidget* parent)
80 : QWidget(parent), ui{std::make_unique<Ui::ConfigureProfileManager>()}, 80 : QWidget(parent), ui{std::make_unique<Ui::ConfigureProfileManager>()},
81 profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_} { 81 profile_manager{system_.GetProfileManager()}, system{system_} {
82 ui->setupUi(this); 82 ui->setupUi(this);
83 83
84 tree_view = new QTreeView; 84 tree_view = new QTreeView;
@@ -149,10 +149,10 @@ void ConfigureProfileManager::SetConfiguration() {
149} 149}
150 150
151void ConfigureProfileManager::PopulateUserList() { 151void ConfigureProfileManager::PopulateUserList() {
152 const auto& profiles = profile_manager->GetAllUsers(); 152 const auto& profiles = profile_manager.GetAllUsers();
153 for (const auto& user : profiles) { 153 for (const auto& user : profiles) {
154 Service::Account::ProfileBase profile{}; 154 Service::Account::ProfileBase profile{};
155 if (!profile_manager->GetProfileBase(user, profile)) 155 if (!profile_manager.GetProfileBase(user, profile))
156 continue; 156 continue;
157 157
158 const auto username = Common::StringFromFixedZeroTerminatedBuffer( 158 const auto username = Common::StringFromFixedZeroTerminatedBuffer(
@@ -167,11 +167,11 @@ void ConfigureProfileManager::PopulateUserList() {
167} 167}
168 168
169void ConfigureProfileManager::UpdateCurrentUser() { 169void ConfigureProfileManager::UpdateCurrentUser() {
170 ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS); 170 ui->pm_add->setEnabled(profile_manager.GetUserCount() < Service::Account::MAX_USERS);
171 171
172 const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue()); 172 const auto& current_user = profile_manager.GetUser(Settings::values.current_user.GetValue());
173 ASSERT(current_user); 173 ASSERT(current_user);
174 const auto username = GetAccountUsername(*profile_manager, *current_user); 174 const auto username = GetAccountUsername(profile_manager, *current_user);
175 175
176 scene->clear(); 176 scene->clear();
177 scene->addPixmap( 177 scene->addPixmap(
@@ -187,11 +187,11 @@ void ConfigureProfileManager::ApplyConfiguration() {
187 187
188void ConfigureProfileManager::SelectUser(const QModelIndex& index) { 188void ConfigureProfileManager::SelectUser(const QModelIndex& index) {
189 Settings::values.current_user = 189 Settings::values.current_user =
190 std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager->GetUserCount() - 1)); 190 std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager.GetUserCount() - 1));
191 191
192 UpdateCurrentUser(); 192 UpdateCurrentUser();
193 193
194 ui->pm_remove->setEnabled(profile_manager->GetUserCount() >= 2); 194 ui->pm_remove->setEnabled(profile_manager.GetUserCount() >= 2);
195 ui->pm_rename->setEnabled(true); 195 ui->pm_rename->setEnabled(true);
196 ui->pm_set_image->setEnabled(true); 196 ui->pm_set_image->setEnabled(true);
197} 197}
@@ -204,18 +204,18 @@ void ConfigureProfileManager::AddUser() {
204 } 204 }
205 205
206 const auto uuid = Common::UUID::MakeRandom(); 206 const auto uuid = Common::UUID::MakeRandom();
207 profile_manager->CreateNewUser(uuid, username.toStdString()); 207 profile_manager.CreateNewUser(uuid, username.toStdString());
208 208
209 item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); 209 item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
210} 210}
211 211
212void ConfigureProfileManager::RenameUser() { 212void ConfigureProfileManager::RenameUser() {
213 const auto user = tree_view->currentIndex().row(); 213 const auto user = tree_view->currentIndex().row();
214 const auto uuid = profile_manager->GetUser(user); 214 const auto uuid = profile_manager.GetUser(user);
215 ASSERT(uuid); 215 ASSERT(uuid);
216 216
217 Service::Account::ProfileBase profile{}; 217 Service::Account::ProfileBase profile{};
218 if (!profile_manager->GetProfileBase(*uuid, profile)) 218 if (!profile_manager.GetProfileBase(*uuid, profile))
219 return; 219 return;
220 220
221 const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:")); 221 const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:"));
@@ -227,7 +227,7 @@ void ConfigureProfileManager::RenameUser() {
227 std::fill(profile.username.begin(), profile.username.end(), '\0'); 227 std::fill(profile.username.begin(), profile.username.end(), '\0');
228 std::copy(username_std.begin(), username_std.end(), profile.username.begin()); 228 std::copy(username_std.begin(), username_std.end(), profile.username.begin());
229 229
230 profile_manager->SetProfileBase(*uuid, profile); 230 profile_manager.SetProfileBase(*uuid, profile);
231 231
232 item_model->setItem( 232 item_model->setItem(
233 user, 0, 233 user, 0,
@@ -238,9 +238,9 @@ void ConfigureProfileManager::RenameUser() {
238 238
239void ConfigureProfileManager::ConfirmDeleteUser() { 239void ConfigureProfileManager::ConfirmDeleteUser() {
240 const auto index = tree_view->currentIndex().row(); 240 const auto index = tree_view->currentIndex().row();
241 const auto uuid = profile_manager->GetUser(index); 241 const auto uuid = profile_manager.GetUser(index);
242 ASSERT(uuid); 242 ASSERT(uuid);
243 const auto username = GetAccountUsername(*profile_manager, *uuid); 243 const auto username = GetAccountUsername(profile_manager, *uuid);
244 244
245 confirm_dialog->SetInfo(username, *uuid, [this, uuid]() { DeleteUser(*uuid); }); 245 confirm_dialog->SetInfo(username, *uuid, [this, uuid]() { DeleteUser(*uuid); });
246 confirm_dialog->show(); 246 confirm_dialog->show();
@@ -252,7 +252,7 @@ void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) {
252 } 252 }
253 UpdateCurrentUser(); 253 UpdateCurrentUser();
254 254
255 if (!profile_manager->RemoveUser(uuid)) { 255 if (!profile_manager.RemoveUser(uuid)) {
256 return; 256 return;
257 } 257 }
258 258
@@ -265,7 +265,7 @@ void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) {
265 265
266void ConfigureProfileManager::SetUserImage() { 266void ConfigureProfileManager::SetUserImage() {
267 const auto index = tree_view->currentIndex().row(); 267 const auto index = tree_view->currentIndex().row();
268 const auto uuid = profile_manager->GetUser(index); 268 const auto uuid = profile_manager.GetUser(index);
269 ASSERT(uuid); 269 ASSERT(uuid);
270 270
271 const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), 271 const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(),
@@ -317,7 +317,7 @@ void ConfigureProfileManager::SetUserImage() {
317 } 317 }
318 } 318 }
319 319
320 const auto username = GetAccountUsername(*profile_manager, *uuid); 320 const auto username = GetAccountUsername(profile_manager, *uuid);
321 item_model->setItem(index, 0, 321 item_model->setItem(index, 0,
322 new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)}); 322 new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)});
323 UpdateCurrentUser(); 323 UpdateCurrentUser();
diff --git a/src/yuzu/configuration/configure_profile_manager.h b/src/yuzu/configuration/configure_profile_manager.h
index c4b1a334e..39560fdd9 100644
--- a/src/yuzu/configuration/configure_profile_manager.h
+++ b/src/yuzu/configuration/configure_profile_manager.h
@@ -52,7 +52,7 @@ class ConfigureProfileManager : public QWidget {
52 Q_OBJECT 52 Q_OBJECT
53 53
54public: 54public:
55 explicit ConfigureProfileManager(const Core::System& system_, QWidget* parent = nullptr); 55 explicit ConfigureProfileManager(Core::System& system_, QWidget* parent = nullptr);
56 ~ConfigureProfileManager() override; 56 ~ConfigureProfileManager() override;
57 57
58 void ApplyConfiguration(); 58 void ApplyConfiguration();
@@ -85,7 +85,6 @@ private:
85 std::unique_ptr<Ui::ConfigureProfileManager> ui; 85 std::unique_ptr<Ui::ConfigureProfileManager> ui;
86 bool enabled = false; 86 bool enabled = false;
87 87
88 std::unique_ptr<Service::Account::ProfileManager> profile_manager; 88 Service::Account::ProfileManager& profile_manager;
89
90 const Core::System& system; 89 const Core::System& system;
91}; 90};
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 6d227ef8d..c05a05057 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -7,7 +7,7 @@
7#include "yuzu/debugger/wait_tree.h" 7#include "yuzu/debugger/wait_tree.h"
8#include "yuzu/uisettings.h" 8#include "yuzu/uisettings.h"
9 9
10#include "core/arm/arm_interface.h" 10#include "core/arm/debug.h"
11#include "core/core.h" 11#include "core/core.h"
12#include "core/hle/kernel/k_class_token.h" 12#include "core/hle/kernel/k_class_token.h"
13#include "core/hle/kernel/k_handle_table.h" 13#include "core/hle/kernel/k_handle_table.h"
@@ -129,7 +129,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
129 return list; 129 return list;
130 } 130 }
131 131
132 auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(system, thread.GetContext64()); 132 auto backtrace = Core::GetBacktraceFromContext(thread.GetOwnerProcess(), thread.GetContext());
133 133
134 for (auto& entry : backtrace) { 134 for (auto& entry : backtrace) {
135 std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, 135 std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
@@ -238,10 +238,10 @@ QString WaitTreeThread::GetText() const {
238 break; 238 break;
239 } 239 }
240 240
241 const auto& context = thread.GetContext64(); 241 const auto& context = thread.GetContext();
242 const QString pc_info = tr(" PC = 0x%1 LR = 0x%2") 242 const QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
243 .arg(context.pc, 8, 16, QLatin1Char{'0'}) 243 .arg(context.pc, 8, 16, QLatin1Char{'0'})
244 .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'}); 244 .arg(context.lr, 8, 16, QLatin1Char{'0'});
245 return QStringLiteral("%1%2 (%3) ") 245 return QStringLiteral("%1%2 (%3) ")
246 .arg(WaitTreeSynchronizationObject::GetText(), pc_info, status); 246 .arg(WaitTreeSynchronizationObject::GetText(), pc_info, status);
247} 247}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b056c3717..f31ed7ebb 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -346,7 +346,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
346 SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); 346 SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue());
347 discord_rpc->Update(); 347 discord_rpc->Update();
348 348
349 play_time_manager = std::make_unique<PlayTime::PlayTimeManager>(); 349 play_time_manager = std::make_unique<PlayTime::PlayTimeManager>(system->GetProfileManager());
350 350
351 system->GetRoomNetwork().Init(); 351 system->GetRoomNetwork().Init();
352 352
@@ -526,8 +526,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk
526 continue; 526 continue;
527 } 527 }
528 528
529 const Service::Account::ProfileManager manager; 529 if (!system->GetProfileManager().UserExistsIndex(selected_user)) {
530 if (!manager.UserExistsIndex(selected_user)) {
531 LOG_ERROR(Frontend, "Selected user doesn't exist"); 530 LOG_ERROR(Frontend, "Selected user doesn't exist");
532 continue; 531 continue;
533 } 532 }
@@ -691,7 +690,7 @@ void GMainWindow::ControllerSelectorRequestExit() {
691 690
692void GMainWindow::ProfileSelectorSelectProfile( 691void GMainWindow::ProfileSelectorSelectProfile(
693 const Core::Frontend::ProfileSelectParameters& parameters) { 692 const Core::Frontend::ProfileSelectParameters& parameters) {
694 profile_select_applet = new QtProfileSelectionDialog(system->HIDCore(), this, parameters); 693 profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters);
695 SCOPE_EXIT({ 694 SCOPE_EXIT({
696 profile_select_applet->deleteLater(); 695 profile_select_applet->deleteLater();
697 profile_select_applet = nullptr; 696 profile_select_applet = nullptr;
@@ -706,8 +705,8 @@ void GMainWindow::ProfileSelectorSelectProfile(
706 return; 705 return;
707 } 706 }
708 707
709 const Service::Account::ProfileManager manager; 708 const auto uuid = system->GetProfileManager().GetUser(
710 const auto uuid = manager.GetUser(static_cast<std::size_t>(profile_select_applet->GetIndex())); 709 static_cast<std::size_t>(profile_select_applet->GetIndex()));
711 if (!uuid.has_value()) { 710 if (!uuid.has_value()) {
712 emit ProfileSelectorFinishedSelection(std::nullopt); 711 emit ProfileSelectorFinishedSelection(std::nullopt);
713 return; 712 return;
@@ -1856,7 +1855,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
1856 1855
1857bool GMainWindow::SelectAndSetCurrentUser( 1856bool GMainWindow::SelectAndSetCurrentUser(
1858 const Core::Frontend::ProfileSelectParameters& parameters) { 1857 const Core::Frontend::ProfileSelectParameters& parameters) {
1859 QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters); 1858 QtProfileSelectionDialog dialog(*system, this, parameters);
1860 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | 1859 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
1861 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); 1860 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
1862 dialog.setWindowModality(Qt::WindowModal); 1861 dialog.setWindowModality(Qt::WindowModal);
@@ -2271,7 +2270,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
2271 .display_options = {}, 2270 .display_options = {},
2272 .purpose = Service::AM::Applets::UserSelectionPurpose::General, 2271 .purpose = Service::AM::Applets::UserSelectionPurpose::General,
2273 }; 2272 };
2274 QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters); 2273 QtProfileSelectionDialog dialog(*system, this, parameters);
2275 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | 2274 dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
2276 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); 2275 Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
2277 dialog.setWindowModality(Qt::WindowModal); 2276 dialog.setWindowModality(Qt::WindowModal);
@@ -2288,8 +2287,8 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
2288 return; 2287 return;
2289 } 2288 }
2290 2289
2291 Service::Account::ProfileManager manager; 2290 const auto user_id =
2292 const auto user_id = manager.GetUser(static_cast<std::size_t>(index)); 2291 system->GetProfileManager().GetUser(static_cast<std::size_t>(index));
2293 ASSERT(user_id); 2292 ASSERT(user_id);
2294 2293
2295 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( 2294 const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp
index 603e9ae3d..41692c05b 100644
--- a/src/yuzu/multiplayer/lobby.cpp
+++ b/src/yuzu/multiplayer/lobby.cpp
@@ -27,9 +27,9 @@
27Lobby::Lobby(QWidget* parent, QStandardItemModel* list, 27Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
28 std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_) 28 std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_)
29 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), 29 : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
30 ui(std::make_unique<Ui::Lobby>()), announce_multiplayer_session(session), 30 ui(std::make_unique<Ui::Lobby>()),
31 profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_}, 31 announce_multiplayer_session(session), system{system_}, room_network{
32 room_network{system.GetRoomNetwork()} { 32 system.GetRoomNetwork()} {
33 ui->setupUi(this); 33 ui->setupUi(this);
34 34
35 // setup the watcher for background connections 35 // setup the watcher for background connections
@@ -299,14 +299,15 @@ void Lobby::OnRefreshLobby() {
299} 299}
300 300
301std::string Lobby::GetProfileUsername() { 301std::string Lobby::GetProfileUsername() {
302 const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue()); 302 const auto& current_user =
303 system.GetProfileManager().GetUser(Settings::values.current_user.GetValue());
303 Service::Account::ProfileBase profile{}; 304 Service::Account::ProfileBase profile{};
304 305
305 if (!current_user.has_value()) { 306 if (!current_user.has_value()) {
306 return ""; 307 return "";
307 } 308 }
308 309
309 if (!profile_manager->GetProfileBase(*current_user, profile)) { 310 if (!system.GetProfileManager().GetProfileBase(*current_user, profile)) {
310 return ""; 311 return "";
311 } 312 }
312 313
diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h
index 2674ae7c3..e78c9cae3 100644
--- a/src/yuzu/multiplayer/lobby.h
+++ b/src/yuzu/multiplayer/lobby.h
@@ -24,10 +24,6 @@ namespace Core {
24class System; 24class System;
25} 25}
26 26
27namespace Service::Account {
28class ProfileManager;
29}
30
31/** 27/**
32 * Listing of all public games pulled from services. The lobby should be simple enough for users to 28 * Listing of all public games pulled from services. The lobby should be simple enough for users to
33 * find the game they want to play, and join it. 29 * find the game they want to play, and join it.
@@ -103,7 +99,6 @@ private:
103 99
104 QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher; 100 QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher;
105 std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; 101 std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
106 std::unique_ptr<Service::Account::ProfileManager> profile_manager;
107 QFutureWatcher<void>* watcher; 102 QFutureWatcher<void>* watcher;
108 Validation validation; 103 Validation validation;
109 Core::System& system; 104 Core::System& system;
diff --git a/src/yuzu/play_time_manager.cpp b/src/yuzu/play_time_manager.cpp
index 155c36b7d..94c99274d 100644
--- a/src/yuzu/play_time_manager.cpp
+++ b/src/yuzu/play_time_manager.cpp
@@ -20,8 +20,8 @@ struct PlayTimeElement {
20 PlayTime play_time; 20 PlayTime play_time;
21}; 21};
22 22
23std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() { 23std::optional<std::filesystem::path> GetCurrentUserPlayTimePath(
24 const Service::Account::ProfileManager manager; 24 const Service::Account::ProfileManager& manager) {
25 const auto uuid = manager.GetUser(static_cast<s32>(Settings::values.current_user)); 25 const auto uuid = manager.GetUser(static_cast<s32>(Settings::values.current_user));
26 if (!uuid.has_value()) { 26 if (!uuid.has_value()) {
27 return std::nullopt; 27 return std::nullopt;
@@ -30,8 +30,9 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() {
30 uuid->RawString().append(".bin"); 30 uuid->RawString().append(".bin");
31} 31}
32 32
33[[nodiscard]] bool ReadPlayTimeFile(PlayTimeDatabase& out_play_time_db) { 33[[nodiscard]] bool ReadPlayTimeFile(PlayTimeDatabase& out_play_time_db,
34 const auto filename = GetCurrentUserPlayTimePath(); 34 const Service::Account::ProfileManager& manager) {
35 const auto filename = GetCurrentUserPlayTimePath(manager);
35 36
36 if (!filename.has_value()) { 37 if (!filename.has_value()) {
37 LOG_ERROR(Frontend, "Failed to get current user path"); 38 LOG_ERROR(Frontend, "Failed to get current user path");
@@ -66,8 +67,9 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() {
66 return true; 67 return true;
67} 68}
68 69
69[[nodiscard]] bool WritePlayTimeFile(const PlayTimeDatabase& play_time_db) { 70[[nodiscard]] bool WritePlayTimeFile(const PlayTimeDatabase& play_time_db,
70 const auto filename = GetCurrentUserPlayTimePath(); 71 const Service::Account::ProfileManager& manager) {
72 const auto filename = GetCurrentUserPlayTimePath(manager);
71 73
72 if (!filename.has_value()) { 74 if (!filename.has_value()) {
73 LOG_ERROR(Frontend, "Failed to get current user path"); 75 LOG_ERROR(Frontend, "Failed to get current user path");
@@ -96,8 +98,9 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() {
96 98
97} // namespace 99} // namespace
98 100
99PlayTimeManager::PlayTimeManager() { 101PlayTimeManager::PlayTimeManager(Service::Account::ProfileManager& profile_manager)
100 if (!ReadPlayTimeFile(database)) { 102 : manager{profile_manager} {
103 if (!ReadPlayTimeFile(database, manager)) {
101 LOG_ERROR(Frontend, "Failed to read play time database! Resetting to default."); 104 LOG_ERROR(Frontend, "Failed to read play time database! Resetting to default.");
102 } 105 }
103} 106}
@@ -142,7 +145,7 @@ void PlayTimeManager::AutoTimestamp(std::stop_token stop_token) {
142} 145}
143 146
144void PlayTimeManager::Save() { 147void PlayTimeManager::Save() {
145 if (!WritePlayTimeFile(database)) { 148 if (!WritePlayTimeFile(database, manager)) {
146 LOG_ERROR(Frontend, "Failed to update play time database!"); 149 LOG_ERROR(Frontend, "Failed to update play time database!");
147 } 150 }
148} 151}
diff --git a/src/yuzu/play_time_manager.h b/src/yuzu/play_time_manager.h
index 5f96f3447..1714b9131 100644
--- a/src/yuzu/play_time_manager.h
+++ b/src/yuzu/play_time_manager.h
@@ -11,6 +11,10 @@
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/polyfill_thread.h" 12#include "common/polyfill_thread.h"
13 13
14namespace Service::Account {
15class ProfileManager;
16}
17
14namespace PlayTime { 18namespace PlayTime {
15 19
16using ProgramId = u64; 20using ProgramId = u64;
@@ -19,7 +23,7 @@ using PlayTimeDatabase = std::map<ProgramId, PlayTime>;
19 23
20class PlayTimeManager { 24class PlayTimeManager {
21public: 25public:
22 explicit PlayTimeManager(); 26 explicit PlayTimeManager(Service::Account::ProfileManager& profile_manager);
23 ~PlayTimeManager(); 27 ~PlayTimeManager();
24 28
25 YUZU_NON_COPYABLE(PlayTimeManager); 29 YUZU_NON_COPYABLE(PlayTimeManager);
@@ -32,11 +36,13 @@ public:
32 void Stop(); 36 void Stop();
33 37
34private: 38private:
39 void AutoTimestamp(std::stop_token stop_token);
40 void Save();
41
35 PlayTimeDatabase database; 42 PlayTimeDatabase database;
36 u64 running_program_id; 43 u64 running_program_id;
37 std::jthread play_time_thread; 44 std::jthread play_time_thread;
38 void AutoTimestamp(std::stop_token stop_token); 45 Service::Account::ProfileManager& manager;
39 void Save();
40}; 46};
41 47
42QString ReadablePlayTime(qulonglong time_seconds); 48QString ReadablePlayTime(qulonglong time_seconds);