diff options
178 files changed, 7461 insertions, 5347 deletions
diff --git a/.codespellrc b/.codespellrc index d1f998449..1874359d3 100644 --- a/.codespellrc +++ b/.codespellrc @@ -3,4 +3,4 @@ [codespell] skip = ./.git,./build,./dist,./Doxyfile,./externals,./LICENSES,./src/android/app/src/main/res -ignore-words-list = aci,allright,ba,canonicalizations,deques,froms,hda,inout,lod,masia,nam,nax,nce,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink +ignore-words-list = aci,allright,ba,canonicalizations,deques,fpr,froms,hda,inout,lod,masia,nam,nax,nce,nd,optin,pullrequests,pullrequest,te,transfered,unstall,uscaled,vas,zink diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index ea1302b2f..c073f3f3f 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -79,7 +79,8 @@ jobs: fetch-depth: 0 - name: Install dependencies run: | - brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd + # workaround for https://github.com/actions/setup-python/issues/577 + brew install autoconf automake boost@1.83 ccache ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@5 sdl2 speexdsp zlib zlib zstd || brew link --overwrite python@3.12 - name: Build run: | mkdir build diff --git a/dist/72-yuzu-input.rules b/dist/72-yuzu-input.rules new file mode 100644 index 000000000..d64f8b28d --- /dev/null +++ b/dist/72-yuzu-input.rules @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2023 yuzu Emulator Project +# SPDX-License-Identifier: GPL-2.0-or-later + +# Allow systemd-logind to manage user access to hidraw with this file +# On most systems, this file should be installed to /etc/udev/rules.d/72-yuzu-input.rules +# Consult your distro if this is not the case + +# Switch Pro Controller (USB/Bluetooth) +KERNEL=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="2009", MODE="0660", TAG+="uaccess" +KERNEL=="hidraw*", KERNELS=="*057e:2009*", MODE="0660", TAG+="uaccess" + +# Joy-Con L (Bluetooth) +KERNEL=="hidraw*", KERNELS=="*057e:2006*", MODE="0660", TAG+="uaccess" + +# Joy-Con R (Bluetooth) +KERNEL=="hidraw*", KERNELS=="*057e:2007*", MODE="0660", TAG+="uaccess" + +# Joy-Con Charging Grip (USB) +KERNEL=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="200e", MODE="0660", TAG+="uaccess" diff --git a/externals/vcpkg b/externals/vcpkg -Subproject ef2eef17340f3fbd679327d286fad06dd6e838e +Subproject a42af01b72c28a8e1d7b48107b33e4f286a55ef 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 import org.yuzu.yuzu_emu.databinding.DialogAddFolderBinding import org.yuzu.yuzu_emu.model.GameDir import org.yuzu.yuzu_emu.model.GamesViewModel +import org.yuzu.yuzu_emu.model.HomeViewModel class AddGameFolderDialogFragment : DialogFragment() { + private val homeViewModel: HomeViewModel by activityViewModels() private val gamesViewModel: GamesViewModel by activityViewModels() override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { @@ -30,6 +32,7 @@ class AddGameFolderDialogFragment : DialogFragment() { .setTitle(R.string.add_game_folder) .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> val newGameDir = GameDir(folderUriString!!, binding.deepScanSwitch.isChecked) + homeViewModel.setGamesDirSelected(true) gamesViewModel.addFolder(newGameDir) } .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 @@ package org.yuzu.yuzu_emu.fragments import android.Manifest +import android.annotation.SuppressLint import android.content.Intent import android.os.Build import android.os.Bundle @@ -75,6 +76,8 @@ class SetupFragment : Fragment() { return binding.root } + // This is using the correct scope, lint is just acting up + @SuppressLint("UnsafeRepeatOnLifecycleDetector") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { mainActivity = requireActivity() as MainActivity @@ -206,12 +209,24 @@ class SetupFragment : Fragment() { ) } - viewLifecycleOwner.lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.CREATED) { - homeViewModel.shouldPageForward.collect { - if (it) { - pageForward() - homeViewModel.setShouldPageForward(false) + viewLifecycleOwner.lifecycleScope.apply { + launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + homeViewModel.shouldPageForward.collect { + if (it) { + pageForward() + homeViewModel.setShouldPageForward(false) + } + } + } + } + launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + homeViewModel.gamesDirSelected.collect { + if (it) { + gamesDirCallback.onStepCompleted() + homeViewModel.setGamesDirSelected(false) + } } } } @@ -339,7 +354,6 @@ class SetupFragment : Fragment() { registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result -> if (result != null) { mainActivity.processGamesDir(result) - gamesDirCallback.onStepCompleted() } } 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() { viewModelScope.launch { withContext(Dispatchers.IO) { NativeConfig.addGameDir(gameDir) - getGameDirs() + getGameDirs(true) } } 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 import androidx.lifecycle.ViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow class HomeViewModel : ViewModel() { val navigationVisible: StateFlow<Pair<Boolean, Boolean>> get() = _navigationVisible @@ -17,6 +18,9 @@ class HomeViewModel : ViewModel() { val shouldPageForward: StateFlow<Boolean> get() = _shouldPageForward private val _shouldPageForward = MutableStateFlow(false) + private val _gamesDirSelected = MutableStateFlow(false) + val gamesDirSelected get() = _gamesDirSelected.asStateFlow() + var navigatedToSetup = false fun setNavigationVisibility(visible: Boolean, animated: Boolean) { @@ -36,4 +40,8 @@ class HomeViewModel : ViewModel() { fun setShouldPageForward(pageForward: Boolean) { _shouldPageForward.value = pageForward } + + fun setGamesDirSelected(selected: Boolean) { + _gamesDirSelected.value = selected + } } 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 // Initialize filesystem. ConfigureFilesystemProvider(filepath); - // Initialize account manager - m_profile_manager = std::make_unique<Service::Account::ProfileManager>(); - // Load the ROM. m_load_result = m_system.Load(EmulationSession::GetInstance().Window(), filepath); if (m_load_result != Core::SystemResultStatus::Success) { @@ -736,8 +733,8 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv* auto vfs_nand_dir = EmulationSession::GetInstance().System().GetFilesystem()->OpenDirectory( Common::FS::PathToUTF8String(nand_dir), FileSys::Mode::Read); - Service::Account::ProfileManager manager; - const auto user_id = manager.GetUser(static_cast<std::size_t>(0)); + const auto user_id = EmulationSession::GetInstance().System().GetProfileManager().GetUser( + static_cast<std::size_t>(0)); ASSERT(user_id); 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: std::atomic<bool> m_is_running = false; std::atomic<bool> m_is_paused = false; SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; - std::unique_ptr<Service::Account::ProfileManager> m_profile_manager; std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; // 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 @@ #elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv -#ifdef ANDROID -#include <android/sharedmem.h> -#endif - #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif @@ -193,6 +189,11 @@ public: } } + bool ClearBackingRegion(size_t physical_offset, size_t length) { + // TODO: This does not seem to be possible on Windows. + return false; + } + void EnableDirectMappedAddress() { // TODO UNREACHABLE(); @@ -442,9 +443,7 @@ public: } // Backing memory initialization -#ifdef ANDROID - fd = ASharedMemory_create("HostMemory", backing_size); -#elif defined(__FreeBSD__) && __FreeBSD__ < 13 +#if defined(__FreeBSD__) && __FreeBSD__ < 13 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30 fd = shm_open(SHM_ANON, O_RDWR, 0600); #else @@ -455,7 +454,6 @@ public: throw std::bad_alloc{}; } -#ifndef ANDROID // Defined to extend the file with zeros int ret = ftruncate(fd, backing_size); if (ret != 0) { @@ -463,7 +461,6 @@ public: strerror(errno)); throw std::bad_alloc{}; } -#endif backing_base = static_cast<u8*>( mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); @@ -552,6 +549,19 @@ public: ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno)); } + bool ClearBackingRegion(size_t physical_offset, size_t length) { +#ifdef __linux__ + // Set MADV_REMOVE on backing map to destroy it instantly. + // This also deletes the area from the backing file. + int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE); + ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno)); + + return true; +#else + return false; +#endif + } + void EnableDirectMappedAddress() { virtual_base = nullptr; } @@ -623,6 +633,10 @@ public: void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {} + bool ClearBackingRegion(size_t physical_offset, size_t length) { + return false; + } + void EnableDirectMappedAddress() {} u8* backing_base{nullptr}; @@ -698,6 +712,12 @@ void HostMemory::Protect(size_t virtual_offset, size_t length, bool read, bool w impl->Protect(virtual_offset + virtual_base_offset, length, read, write, execute); } +void HostMemory::ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value) { + if (!impl || fill_value != 0 || !impl->ClearBackingRegion(physical_offset, length)) { + std::memset(backing_base + physical_offset, fill_value, length); + } +} + void HostMemory::EnableDirectMappedAddress() { if (impl) { 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: void EnableDirectMappedAddress(); + void ClearBackingRegion(size_t physical_offset, size_t length, u32 fill_value); + [[nodiscard]] u8* BackingBasePointer() noexcept { return backing_base; } 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; void SetNceEnabled(bool is_39bit) { const bool is_nce_selected = values.cpu_backend.GetValue() == CpuBackend::Nce; - is_nce_enabled = IsFastmemEnabled() && is_nce_selected && is_39bit; - if (is_nce_selected && !is_nce_enabled) { + if (is_nce_selected && !IsFastmemEnabled()) { + LOG_WARNING(Common, "Fastmem is required to natively execute code in a performant manner, " + "falling back to Dynarmic"); + } + if (is_nce_selected && !is_39bit) { LOG_WARNING( Common, "Program does not utilize 39-bit address space, unable to natively execute code"); } + is_nce_enabled = IsFastmemEnabled() && is_nce_selected && is_39bit; } bool 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 { &use_speed_limit}; // Cpu - SwitchableSetting<CpuBackend, true> cpu_backend{ - linkage, CpuBackend::Dynarmic, CpuBackend::Dynarmic, + SwitchableSetting<CpuBackend, true> cpu_backend{linkage, #ifdef HAS_NCE - CpuBackend::Nce, + CpuBackend::Nce, #else CpuBackend::Dynarmic, #endif - "cpu_backend", Category::Cpu}; + CpuBackend::Dynarmic, +#ifdef HAS_NCE + CpuBackend::Nce, +#else + CpuBackend::Dynarmic, +#endif + "cpu_backend", + Category::Cpu}; SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto, CpuAccuracy::Auto, CpuAccuracy::Paranoid, "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 @@ add_library(core STATIC arm/arm_interface.h arm/arm_interface.cpp + arm/debug.cpp + arm/debug.h arm/exclusive_monitor.cpp arm/exclusive_monitor.h arm/symbols.cpp @@ -249,10 +251,16 @@ add_library(core STATIC hle/kernel/k_hardware_timer.h hle/kernel/k_interrupt_manager.cpp hle/kernel/k_interrupt_manager.h + hle/kernel/k_light_client_session.cpp + hle/kernel/k_light_client_session.h hle/kernel/k_light_condition_variable.cpp hle/kernel/k_light_condition_variable.h hle/kernel/k_light_lock.cpp hle/kernel/k_light_lock.h + hle/kernel/k_light_server_session.cpp + hle/kernel/k_light_server_session.h + hle/kernel/k_light_session.cpp + hle/kernel/k_light_session.h hle/kernel/k_memory_block.h hle/kernel/k_memory_block_manager.cpp hle/kernel/k_memory_block_manager.h @@ -541,6 +549,13 @@ add_library(core STATIC hle/service/hid/xcd.cpp hle/service/hid/xcd.h hle/service/hid/errors.h + hle/service/hid/controllers/types/debug_pad_types.h + hle/service/hid/controllers/types/keyboard_types.h + hle/service/hid/controllers/types/mouse_types.h + hle/service/hid/controllers/types/npad_types.h + hle/service/hid/controllers/types/touch_types.h + hle/service/hid/controllers/applet_resource.cpp + hle/service/hid/controllers/applet_resource.h hle/service/hid/controllers/console_six_axis.cpp hle/service/hid/controllers/console_six_axis.h hle/service/hid/controllers/controller_base.cpp @@ -559,14 +574,15 @@ add_library(core STATIC hle/service/hid/controllers/palma.h hle/service/hid/controllers/seven_six_axis.cpp hle/service/hid/controllers/seven_six_axis.h + hle/service/hid/controllers/shared_memory_format.h + hle/service/hid/controllers/shared_memory_holder.cpp + hle/service/hid/controllers/shared_memory_holder.h hle/service/hid/controllers/six_axis.cpp hle/service/hid/controllers/six_axis.h hle/service/hid/controllers/stubbed.cpp hle/service/hid/controllers/stubbed.h hle/service/hid/controllers/touchscreen.cpp hle/service/hid/controllers/touchscreen.h - hle/service/hid/controllers/xpad.cpp - hle/service/hid/controllers/xpad.h hle/service/hid/hidbus/hidbus_base.cpp hle/service/hid/hidbus/hidbus_base.h hle/service/hid/hidbus/ringcon.cpp @@ -762,6 +778,12 @@ add_library(core STATIC hle/service/kernel_helpers.h hle/service/mutex.cpp hle/service/mutex.h + hle/service/ro/ro_nro_utils.cpp + hle/service/ro/ro_nro_utils.h + hle/service/ro/ro_results.h + hle/service/ro/ro_types.h + hle/service/ro/ro.cpp + hle/service/ro/ro.h hle/service/server_manager.cpp hle/service/server_manager.h 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <map> -#include <optional> - -#include "common/bit_field.h" -#include "common/common_types.h" -#include "common/demangle.h" #include "common/logging/log.h" #include "core/arm/arm_interface.h" -#include "core/arm/symbols.h" +#include "core/arm/debug.h" #include "core/core.h" -#include "core/debugger/debugger.h" #include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/svc.h" -#include "core/loader/loader.h" -#include "core/memory.h" namespace Core { -constexpr u64 SEGMENT_BASE = 0x7100000000ull; - -std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( - Core::System& system, const ARM_Interface::ThreadContext32& ctx) { - std::vector<BacktraceEntry> out; - auto& memory = system.ApplicationMemory(); - - const auto& reg = ctx.cpu_registers; - u32 pc = reg[15], lr = reg[14], fp = reg[11]; - out.push_back({"", 0, pc, 0, ""}); - - // fp (= r11) points to the last frame record. - // Frame records are two words long: - // fp+0 : pointer to previous frame record - // fp+4 : value of lr for frame - for (size_t i = 0; i < 256; i++) { - out.push_back({"", 0, lr, 0, ""}); - if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) { - break; - } - lr = memory.Read32(fp + 4); - fp = memory.Read32(fp); - } - - SymbolicateBacktrace(system, out); - - return out; -} - -std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( - Core::System& system, const ARM_Interface::ThreadContext64& ctx) { - std::vector<BacktraceEntry> out; - auto& memory = system.ApplicationMemory(); - - const auto& reg = ctx.cpu_registers; - u64 pc = ctx.pc, lr = reg[30], fp = reg[29]; - - out.push_back({"", 0, pc, 0, ""}); - - // fp (= x29) points to the previous frame record. - // Frame records are two words long: - // fp+0 : pointer to previous frame record - // fp+8 : value of lr for frame - for (size_t i = 0; i < 256; i++) { - out.push_back({"", 0, lr, 0, ""}); - if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) { - break; - } - lr = memory.Read64(fp + 8); - fp = memory.Read64(fp); - } - - SymbolicateBacktrace(system, out); - - return out; -} - -void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out) { - std::map<VAddr, std::string> modules; - auto& loader{system.GetAppLoader()}; - if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { - return; - } - - std::map<std::string, Symbols::Symbols> symbols; - for (const auto& module : modules) { - symbols.insert_or_assign(module.second, - Symbols::GetSymbols(module.first, system.ApplicationMemory(), - system.ApplicationProcess()->Is64Bit())); - } - - for (auto& entry : out) { - VAddr base = 0; - for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) { - const auto& module{*iter}; - if (entry.original_address >= module.first) { - entry.module = module.second; - base = module.first; - break; - } - } - - entry.offset = entry.original_address - base; - entry.address = SEGMENT_BASE + entry.offset; - - if (entry.module.empty()) { - entry.module = "unknown"; - } - - const auto symbol_set = symbols.find(entry.module); - if (symbol_set != symbols.end()) { - const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); - if (symbol) { - entry.name = Common::DemangleSymbol(*symbol); - } - } - } -} - -std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { - if (GetArchitecture() == Architecture::Aarch64) { - ThreadContext64 ctx; - SaveContext(ctx); - return GetBacktraceFromContext(system, ctx); - } else { - ThreadContext32 ctx; - SaveContext(ctx); - return GetBacktraceFromContext(system, ctx); - } -} +void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const { + Kernel::Svc::ThreadContext ctx; + this->GetContext(ctx); -void ARM_Interface::LogBacktrace() const { - const VAddr sp = GetSP(); - const VAddr pc = GetPC(); - LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc); + LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", ctx.sp, ctx.pc); LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", "Offset", "Symbol"); LOG_ERROR(Core_ARM, ""); - const auto backtrace = GetBacktrace(); + const auto backtrace = GetBacktraceFromContext(process, ctx); for (const auto& entry : backtrace) { LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, entry.original_address, entry.offset, entry.name); } } -void ARM_Interface::Run() { - using Kernel::StepState; - using Kernel::SuspendType; - - while (true) { - Kernel::KThread* current_thread{Kernel::GetCurrentThreadPointer(system.Kernel())}; - HaltReason hr{}; - - // If the thread is scheduled for termination, exit the thread. - if (current_thread->HasDpc()) { - if (current_thread->IsTerminationRequested()) { - current_thread->Exit(); - UNREACHABLE(); - } - } - - // Notify the debugger and go to sleep if a step was performed - // and this thread has been scheduled again. - if (current_thread->GetStepState() == StepState::StepPerformed) { - system.GetDebugger().NotifyThreadStopped(current_thread); - current_thread->RequestSuspend(SuspendType::Debug); - break; - } - - // Otherwise, run the thread. - system.EnterCPUProfile(); - if (current_thread->GetStepState() == StepState::StepPending) { - hr = StepJit(); - - if (True(hr & HaltReason::StepThread)) { - current_thread->SetStepState(StepState::StepPerformed); - } - } else { - hr = RunJit(); - } - system.ExitCPUProfile(); - - // Notify the debugger and go to sleep if a breakpoint was hit, - // or if the thread is unable to continue for any reason. - if (True(hr & HaltReason::InstructionBreakpoint) || True(hr & HaltReason::PrefetchAbort)) { - if (!True(hr & HaltReason::PrefetchAbort)) { - RewindBreakpointInstruction(); - } - if (system.DebuggerEnabled()) { - system.GetDebugger().NotifyThreadStopped(current_thread); - } else { - LogBacktrace(); - } - current_thread->RequestSuspend(SuspendType::Debug); - break; - } - - // Notify the debugger and go to sleep if a watchpoint was hit. - if (True(hr & HaltReason::DataAbort)) { - if (system.DebuggerEnabled()) { - system.GetDebugger().NotifyThreadWatchpoint(current_thread, *HaltedWatchpoint()); - } else { - LogBacktrace(); - } - current_thread->RequestSuspend(SuspendType::Debug); - break; - } - - // Handle syscalls and scheduling (this may change the current thread/core) - if (True(hr & HaltReason::SupervisorCall)) { - Kernel::Svc::Call(system, GetSvcNumber()); - break; - } - if (True(hr & HaltReason::BreakLoop) || !uses_wall_clock) { - break; - } - } -} - -void ARM_Interface::LoadWatchpointArray(const WatchpointArray* wp) { - watchpoints = wp; -} - -const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint( +const Kernel::DebugWatchpoint* ArmInterface::MatchingWatchpoint( u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const { - if (!watchpoints) { + if (!m_watchpoints) { return nullptr; } @@ -233,7 +34,7 @@ const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint( const u64 end_address{addr + size}; for (size_t i = 0; i < Core::Hardware::NUM_WATCHPOINTS; i++) { - const auto& watch{(*watchpoints)[i]}; + const auto& watch{(*m_watchpoints)[i]}; if (end_address <= GetInteger(watch.start_address)) { 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 @@ #include "common/common_types.h" #include "core/hardware_properties.h" +#include "core/hle/kernel/svc_types.h" + namespace Common { struct PageTable; } namespace Kernel { -enum class VMAPermission : u8; enum class DebugWatchpointType : u8; struct DebugWatchpoint; +class KThread; +class KProcess; } // namespace Kernel namespace Core { -class System; -class CPUInterruptHandler; - using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>; // NOTE: these values match the HaltReason enum in Dynarmic @@ -40,197 +40,74 @@ enum class HaltReason : u64 { DECLARE_ENUM_FLAG_OPERATORS(HaltReason); enum class Architecture { - Aarch32, - Aarch64, + AArch64, + AArch32, }; /// Generic ARMv8 CPU interface -class ARM_Interface { +class ArmInterface { public: - YUZU_NON_COPYABLE(ARM_Interface); - YUZU_NON_MOVEABLE(ARM_Interface); - - explicit ARM_Interface(System& system_, bool uses_wall_clock_) - : system{system_}, uses_wall_clock{uses_wall_clock_} {} - virtual ~ARM_Interface() = default; - - struct ThreadContext32 { - std::array<u32, 16> cpu_registers{}; - std::array<u32, 64> extension_registers{}; - u32 cpsr{}; - u32 fpscr{}; - u32 fpexc{}; - u32 tpidr{}; - }; - // Internally within the kernel, it expects the AArch32 version of the - // thread context to be 344 bytes in size. - static_assert(sizeof(ThreadContext32) == 0x150); - - struct ThreadContext64 { - std::array<u64, 31> cpu_registers{}; - u64 sp{}; - u64 pc{}; - u32 pstate{}; - std::array<u8, 4> padding{}; - std::array<u128, 32> vector_registers{}; - u32 fpcr{}; - u32 fpsr{}; - u64 tpidr{}; - }; - // Internally within the kernel, it expects the AArch64 version of the - // thread context to be 800 bytes in size. - static_assert(sizeof(ThreadContext64) == 0x320); - - /// Perform any backend-specific initialization. + YUZU_NON_COPYABLE(ArmInterface); + YUZU_NON_MOVEABLE(ArmInterface); + + explicit ArmInterface(bool uses_wall_clock) : m_uses_wall_clock{uses_wall_clock} {} + virtual ~ArmInterface() = default; + + // Perform any backend-specific initialization. virtual void Initialize() {} - /// Runs the CPU until an event happens - void Run(); + // Runs the CPU until an event happens. + virtual HaltReason RunThread(Kernel::KThread* thread) = 0; - /// Clear all instruction cache + // Runs the CPU for one instruction or until an event happens. + virtual HaltReason StepThread(Kernel::KThread* thread) = 0; + + // Admits a backend-specific mechanism to lock the thread context. + virtual void LockThread(Kernel::KThread* thread) {} + virtual void UnlockThread(Kernel::KThread* thread) {} + + // Clear the entire instruction cache for this CPU. virtual void ClearInstructionCache() = 0; - /** - * Clear instruction cache range - * @param addr Start address of the cache range to clear - * @param size Size of the cache range to clear, starting at addr - */ + // Clear a range of the instruction cache for this CPU. virtual void InvalidateCacheRange(u64 addr, std::size_t size) = 0; - /** - * Notifies CPU emulation that the current page table has changed. - * @param new_page_table The new page table. - * @param new_address_space_size_in_bits The new usable size of the address space in bits. - * This can be either 32, 36, or 39 on official software. - */ - virtual void PageTableChanged(Common::PageTable& new_page_table, - std::size_t new_address_space_size_in_bits) = 0; - - /** - * Set the Program Counter to an address - * @param addr Address to set PC to - */ - virtual void SetPC(u64 addr) = 0; - - /* - * Get the current Program Counter - * @return Returns current PC - */ - virtual u64 GetPC() const = 0; - - /** - * Get the current Stack Pointer - * @return Returns current SP - */ - virtual u64 GetSP() const = 0; - - /** - * Get an ARM register - * @param index Register index - * @return Returns the value in the register - */ - virtual u64 GetReg(int index) const = 0; - - /** - * Set an ARM register - * @param index Register index - * @param value Value to set register to - */ - virtual void SetReg(int index, u64 value) = 0; - - /** - * Gets the value of a specified vector register. - * - * @param index The index of the vector register. - * @return the value within the vector register. - */ - virtual u128 GetVectorReg(int index) const = 0; - - /** - * Sets a given value into a vector register. - * - * @param index The index of the vector register. - * @param value The new value to place in the register. - */ - virtual void SetVectorReg(int index, u128 value) = 0; - - /** - * Get the current PSTATE register - * @return Returns the value of the PSTATE register - */ - virtual u32 GetPSTATE() const = 0; - - /** - * Set the current PSTATE register - * @param pstate Value to set PSTATE to - */ - virtual void SetPSTATE(u32 pstate) = 0; - - virtual u64 GetTlsAddress() const = 0; - - virtual void SetTlsAddress(u64 address) = 0; - - /** - * Gets the value within the TPIDR_EL0 (read/write software thread ID) register. - * - * @return the value within the register. - */ - virtual u64 GetTPIDR_EL0() const = 0; - - /** - * Sets a new value within the TPIDR_EL0 (read/write software thread ID) register. - * - * @param value The new value to place in the register. - */ - virtual void SetTPIDR_EL0(u64 value) = 0; - + // Get the current architecture. + // This returns AArch64 when PSTATE.nRW == 0 and AArch32 when PSTATE.nRW == 1. virtual Architecture GetArchitecture() const = 0; - virtual void SaveContext(ThreadContext32& ctx) const = 0; - virtual void SaveContext(ThreadContext64& ctx) const = 0; - virtual void LoadContext(const ThreadContext32& ctx) = 0; - virtual void LoadContext(const ThreadContext64& ctx) = 0; - void LoadWatchpointArray(const WatchpointArray* wp); - /// Clears the exclusive monitor's state. - virtual void ClearExclusiveState() = 0; + // Context accessors. + // These should not be called if the CPU is running. + virtual void GetContext(Kernel::Svc::ThreadContext& ctx) const = 0; + virtual void SetContext(const Kernel::Svc::ThreadContext& ctx) = 0; + virtual void SetTpidrroEl0(u64 value) = 0; - /// Signal an interrupt and ask the core to halt as soon as possible. - virtual void SignalInterrupt() = 0; + virtual void GetSvcArguments(std::span<uint64_t, 8> args) const = 0; + virtual void SetSvcArguments(std::span<const uint64_t, 8> args) = 0; + virtual u32 GetSvcNumber() const = 0; - /// Clear a previous interrupt. - virtual void ClearInterrupt() = 0; + void SetWatchpointArray(const WatchpointArray* watchpoints) { + m_watchpoints = watchpoints; + } - struct BacktraceEntry { - std::string module; - u64 address; - u64 original_address; - u64 offset; - std::string name; - }; + // Signal an interrupt for execution to halt as soon as possible. + // It is safe to call this if the CPU is not running. + virtual void SignalInterrupt(Kernel::KThread* thread) = 0; - static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, - const ThreadContext32& ctx); - static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, - const ThreadContext64& ctx); + // Stack trace generation. + void LogBacktrace(const Kernel::KProcess* process) const; - std::vector<BacktraceEntry> GetBacktrace() const; - void LogBacktrace() const; + // Debug functionality. + virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; + virtual void RewindBreakpointInstruction() = 0; protected: - /// System context that this ARM interface is running under. - System& system; - const WatchpointArray* watchpoints; - bool uses_wall_clock; - - static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out); const Kernel::DebugWatchpoint* MatchingWatchpoint( u64 addr, u64 size, Kernel::DebugWatchpointType access_type) const; - virtual HaltReason RunJit() = 0; - virtual HaltReason StepJit() = 0; - virtual u32 GetSvcNumber() const = 0; - virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; - virtual void RewindBreakpointInstruction() = 0; +protected: + const WatchpointArray* m_watchpoints{}; + bool m_uses_wall_clock{}; }; } // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/demangle.h" +#include "core/arm/debug.h" +#include "core/arm/symbols.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_thread.h" +#include "core/memory.h" + +namespace Core { + +namespace { + +std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory, + const Kernel::KThread& thread) { + // Read thread type from TLS + const VAddr tls_thread_type{memory.Read64(thread.GetTlsAddress() + 0x1f8)}; + const VAddr argument_thread_type{thread.GetArgument()}; + + if (argument_thread_type && tls_thread_type != argument_thread_type) { + // Probably not created by nnsdk, no name available. + return std::nullopt; + } + + if (!tls_thread_type) { + return std::nullopt; + } + + const u16 version{memory.Read16(tls_thread_type + 0x46)}; + VAddr name_pointer{}; + if (version == 1) { + name_pointer = memory.Read64(tls_thread_type + 0x1a0); + } else { + name_pointer = memory.Read64(tls_thread_type + 0x1a8); + } + + if (!name_pointer) { + // No name provided. + return std::nullopt; + } + + return memory.ReadCString(name_pointer, 256); +} + +std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory, + const Kernel::KThread& thread) { + // Read thread type from TLS + const VAddr tls_thread_type{memory.Read32(thread.GetTlsAddress() + 0x1fc)}; + const VAddr argument_thread_type{thread.GetArgument()}; + + if (argument_thread_type && tls_thread_type != argument_thread_type) { + // Probably not created by nnsdk, no name available. + return std::nullopt; + } + + if (!tls_thread_type) { + return std::nullopt; + } + + const u16 version{memory.Read16(tls_thread_type + 0x26)}; + VAddr name_pointer{}; + if (version == 1) { + name_pointer = memory.Read32(tls_thread_type + 0xe4); + } else { + name_pointer = memory.Read32(tls_thread_type + 0xe8); + } + + if (!name_pointer) { + // No name provided. + return std::nullopt; + } + + return memory.ReadCString(name_pointer, 256); +} + +constexpr std::array<u64, 2> SegmentBases{ + 0x60000000ULL, + 0x7100000000ULL, +}; + +void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) { + auto modules = FindModules(process); + + const bool is_64 = process->Is64Bit(); + + std::map<std::string, Symbols::Symbols> symbols; + for (const auto& module : modules) { + symbols.insert_or_assign(module.second, + Symbols::GetSymbols(module.first, process->GetMemory(), is_64)); + } + + for (auto& entry : out) { + VAddr base = 0; + for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) { + const auto& module{*iter}; + if (entry.original_address >= module.first) { + entry.module = module.second; + base = module.first; + break; + } + } + + entry.offset = entry.original_address - base; + entry.address = SegmentBases[is_64] + entry.offset; + + if (entry.module.empty()) { + entry.module = "unknown"; + } + + const auto symbol_set = symbols.find(entry.module); + if (symbol_set != symbols.end()) { + const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); + if (symbol) { + entry.name = Common::DemangleSymbol(*symbol); + } + } + } +} + +std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process, + const Kernel::Svc::ThreadContext& ctx) { + std::vector<BacktraceEntry> out; + auto& memory = process->GetMemory(); + auto pc = ctx.pc, lr = ctx.lr, fp = ctx.fp; + + out.push_back({"", 0, pc, 0, ""}); + + // fp (= x29) points to the previous frame record. + // Frame records are two words long: + // fp+0 : pointer to previous frame record + // fp+8 : value of lr for frame + for (size_t i = 0; i < 256; i++) { + out.push_back({"", 0, lr, 0, ""}); + if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) { + break; + } + lr = memory.Read64(fp + 8); + fp = memory.Read64(fp); + } + + SymbolicateBacktrace(process, out); + + return out; +} + +std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process, + const Kernel::Svc::ThreadContext& ctx) { + std::vector<BacktraceEntry> out; + auto& memory = process->GetMemory(); + auto pc = ctx.pc, lr = ctx.lr, fp = ctx.fp; + + out.push_back({"", 0, pc, 0, ""}); + + // fp (= r11) points to the last frame record. + // Frame records are two words long: + // fp+0 : pointer to previous frame record + // fp+4 : value of lr for frame + for (size_t i = 0; i < 256; i++) { + out.push_back({"", 0, lr, 0, ""}); + if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) { + break; + } + lr = memory.Read32(fp + 4); + fp = memory.Read32(fp); + } + + SymbolicateBacktrace(process, out); + + return out; +} + +} // namespace + +std::optional<std::string> GetThreadName(const Kernel::KThread* thread) { + const auto* process = thread->GetOwnerProcess(); + if (process->Is64Bit()) { + return GetNameFromThreadType64(process->GetMemory(), *thread); + } else { + return GetNameFromThreadType32(process->GetMemory(), *thread); + } +} + +std::string_view GetThreadWaitReason(const Kernel::KThread* thread) { + switch (thread->GetWaitReasonForDebugging()) { + case Kernel::ThreadWaitReasonForDebugging::Sleep: + return "Sleep"; + case Kernel::ThreadWaitReasonForDebugging::IPC: + return "IPC"; + case Kernel::ThreadWaitReasonForDebugging::Synchronization: + return "Synchronization"; + case Kernel::ThreadWaitReasonForDebugging::ConditionVar: + return "ConditionVar"; + case Kernel::ThreadWaitReasonForDebugging::Arbitration: + return "Arbitration"; + case Kernel::ThreadWaitReasonForDebugging::Suspended: + return "Suspended"; + default: + return "Unknown"; + } +} + +std::string GetThreadState(const Kernel::KThread* thread) { + switch (thread->GetState()) { + case Kernel::ThreadState::Initialized: + return "Initialized"; + case Kernel::ThreadState::Waiting: + return fmt::format("Waiting ({})", GetThreadWaitReason(thread)); + case Kernel::ThreadState::Runnable: + return "Runnable"; + case Kernel::ThreadState::Terminated: + return "Terminated"; + default: + return "Unknown"; + } +} + +Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, + Kernel::KProcessAddress base) { + Kernel::KMemoryInfo mem_info; + Kernel::Svc::MemoryInfo svc_mem_info; + Kernel::Svc::PageInfo page_info; + VAddr cur_addr{GetInteger(base)}; + auto& page_table = process->GetPageTable(); + + // Expect: r-x Code (.text) + R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); + svc_mem_info = mem_info.GetSvcMemoryInfo(); + cur_addr = svc_mem_info.base_address + svc_mem_info.size; + if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || + svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) { + return cur_addr - 1; + } + + // Expect: r-- Code (.rodata) + R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); + svc_mem_info = mem_info.GetSvcMemoryInfo(); + cur_addr = svc_mem_info.base_address + svc_mem_info.size; + if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || + svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) { + return cur_addr - 1; + } + + // Expect: rw- CodeData (.data) + R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); + svc_mem_info = mem_info.GetSvcMemoryInfo(); + cur_addr = svc_mem_info.base_address + svc_mem_info.size; + return cur_addr - 1; +} + +Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) { + Loader::AppLoader::Modules modules; + + auto& page_table = process->GetPageTable(); + auto& memory = process->GetMemory(); + VAddr cur_addr = 0; + + // Look for executable sections in Code or AliasCode regions. + while (true) { + Kernel::KMemoryInfo mem_info{}; + Kernel::Svc::PageInfo page_info{}; + R_ASSERT( + page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); + auto svc_mem_info = mem_info.GetSvcMemoryInfo(); + + if (svc_mem_info.permission == Kernel::Svc::MemoryPermission::ReadExecute && + (svc_mem_info.state == Kernel::Svc::MemoryState::Code || + svc_mem_info.state == Kernel::Svc::MemoryState::AliasCode)) { + // Try to read the module name from its path. + constexpr s32 PathLengthMax = 0x200; + struct { + u32 zero; + s32 path_length; + std::array<char, PathLengthMax> path; + } module_path; + + if (memory.ReadBlock(svc_mem_info.base_address + svc_mem_info.size, &module_path, + sizeof(module_path))) { + if (module_path.zero == 0 && module_path.path_length > 0) { + // Truncate module name. + module_path.path[PathLengthMax - 1] = '\0'; + + // Ignore leading directories. + char* path_pointer = module_path.path.data(); + char* path_end = + path_pointer + std::min(PathLengthMax, module_path.path_length); + + for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) && + module_path.path[i] != '\0'; + i++) { + if (module_path.path[i] == '/' || module_path.path[i] == '\\') { + path_pointer = module_path.path.data() + i + 1; + } + } + + // Insert output. + modules.emplace(svc_mem_info.base_address, + std::string_view(path_pointer, path_end)); + } + } + } + + // Check if we're done. + const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size; + if (next_address <= cur_addr) { + break; + } + + cur_addr = next_address; + } + + return modules; +} + +Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) { + // Do we have any loaded executable sections? + auto modules = FindModules(process); + + if (modules.size() >= 2) { + // If we have two or more, the first one is rtld and the second is main. + return std::next(modules.begin())->first; + } else if (!modules.empty()) { + // If we only have one, this is the main module. + return modules.begin()->first; + } + + // As a last resort, use the start of the code region. + return GetInteger(process->GetPageTable().GetCodeRegionStart()); +} + +void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size) { + for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + auto* interface = process->GetArmInterface(i); + if (interface) { + interface->InvalidateCacheRange(address, size); + } + } +} + +std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process, + const Kernel::Svc::ThreadContext& ctx) { + if (process->Is64Bit()) { + return GetAArch64Backtrace(process, ctx); + } else { + return GetAArch32Backtrace(process, ctx); + } +} + +std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread) { + Kernel::Svc::ThreadContext ctx = thread->GetContext(); + return GetBacktraceFromContext(thread->GetOwnerProcess(), ctx); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <optional> + +#include "core/hle/kernel/k_thread.h" +#include "core/loader/loader.h" + +namespace Core { + +std::optional<std::string> GetThreadName(const Kernel::KThread* thread); +std::string_view GetThreadWaitReason(const Kernel::KThread* thread); +std::string GetThreadState(const Kernel::KThread* thread); + +Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process); +Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base); +Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process); + +void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size); + +struct BacktraceEntry { + std::string module; + u64 address; + u64 original_address; + u64 offset; + std::string name; +}; + +std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process, + const Kernel::Svc::ThreadContext& ctx); +std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread); + +} // 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 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <cinttypes> -#include <memory> -#include <dynarmic/interface/A32/a32.h> -#include <dynarmic/interface/A32/config.h> -#include "common/assert.h" -#include "common/literals.h" -#include "common/logging/log.h" -#include "common/page_table.h" #include "common/settings.h" #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/dynarmic_cp15.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" -#include "core/core.h" #include "core/core_timing.h" -#include "core/debugger/debugger.h" #include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/svc.h" -#include "core/memory.h" namespace Core { @@ -27,78 +15,78 @@ using namespace Common::Literals; class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { public: - explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_) - : parent{parent_}, memory(parent.system.ApplicationMemory()), - debugger_enabled{parent.system.DebuggerEnabled()}, - check_memory_access{debugger_enabled || - !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} + explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process) + : m_parent{parent}, m_memory(process->GetMemory()), + m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, + m_check_memory_access{m_debugger_enabled || + !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} u8 MemoryRead8(u32 vaddr) override { CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); - return memory.Read8(vaddr); + return m_memory.Read8(vaddr); } u16 MemoryRead16(u32 vaddr) override { CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); - return memory.Read16(vaddr); + return m_memory.Read16(vaddr); } u32 MemoryRead32(u32 vaddr) override { CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); - return memory.Read32(vaddr); + return m_memory.Read32(vaddr); } u64 MemoryRead64(u32 vaddr) override { CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); - return memory.Read64(vaddr); + return m_memory.Read64(vaddr); } std::optional<u32> MemoryReadCode(u32 vaddr) override { - if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { + if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { return std::nullopt; } - return memory.Read32(vaddr); + return m_memory.Read32(vaddr); } void MemoryWrite8(u32 vaddr, u8 value) override { if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { - memory.Write8(vaddr, value); + m_memory.Write8(vaddr, value); } } void MemoryWrite16(u32 vaddr, u16 value) override { if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { - memory.Write16(vaddr, value); + m_memory.Write16(vaddr, value); } } void MemoryWrite32(u32 vaddr, u32 value) override { if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { - memory.Write32(vaddr, value); + m_memory.Write32(vaddr, value); } } void MemoryWrite64(u32 vaddr, u64 value) override { if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { - memory.Write64(vaddr, value); + m_memory.Write64(vaddr, value); } } bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override { return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive8(vaddr, value, expected); + m_memory.WriteExclusive8(vaddr, value, expected); } bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override { return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive16(vaddr, value, expected); + m_memory.WriteExclusive16(vaddr, value, expected); } bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override { return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive32(vaddr, value, expected); + m_memory.WriteExclusive32(vaddr, value, expected); } bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override { return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive64(vaddr, value, expected); + m_memory.WriteExclusive64(vaddr, value, expected); } void InterpreterFallback(u32 pc, std::size_t num_instructions) override { - parent.LogBacktrace(); + m_parent.LogBacktrace(m_process); LOG_ERROR(Core_ARM, "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, - num_instructions, memory.Read32(pc)); + num_instructions, m_memory.Read32(pc)); } void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override { @@ -108,73 +96,64 @@ public: ReturnException(pc, PrefetchAbort); return; default: - if (debugger_enabled) { + if (m_debugger_enabled) { ReturnException(pc, InstructionBreakpoint); return; } - parent.LogBacktrace(); + m_parent.LogBacktrace(m_process); LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})", - exception, pc, memory.Read32(pc), parent.IsInThumbMode()); + exception, pc, m_memory.Read32(pc), m_parent.IsInThumbMode()); } } void CallSVC(u32 swi) override { - parent.svc_swi = swi; - parent.jit.load()->HaltExecution(SupervisorCall); + m_parent.m_svc_swi = swi; + m_parent.m_jit->HaltExecution(SupervisorCall); } void AddTicks(u64 ticks) override { - if (parent.uses_wall_clock) { - return; - } + ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled"); // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a // rough approximation of the amount of executed ticks in the system, it may be thrown off // if not all cores are doing a similar amount of work. Instead of doing this, we should // device a way so that timing is consistent across all cores without increasing the ticks 4 // times. - u64 amortized_ticks = - (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES; + u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES; // Always execute at least one tick. amortized_ticks = std::max<u64>(amortized_ticks, 1); - parent.system.CoreTiming().AddTicks(amortized_ticks); - num_interpreted_instructions = 0; + m_parent.m_system.CoreTiming().AddTicks(amortized_ticks); } u64 GetTicksRemaining() override { - if (parent.uses_wall_clock) { - if (!IsInterrupted()) { - return minimum_run_cycles; - } - return 0U; - } + ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled"); - return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); + return std::max<s64>(m_parent.m_system.CoreTiming().GetDowncount(), 0); } bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) { - if (!check_memory_access) { + if (!m_check_memory_access) { return true; } - if (!memory.IsValidVirtualAddressRange(addr, size)) { + if (!m_memory.IsValidVirtualAddressRange(addr, size)) { LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}", addr); - parent.jit.load()->HaltExecution(PrefetchAbort); + m_parent.m_jit->HaltExecution(PrefetchAbort); return false; } - if (!debugger_enabled) { + if (!m_debugger_enabled) { return true; } - const auto match{parent.MatchingWatchpoint(addr, size, type)}; + const auto match{m_parent.MatchingWatchpoint(addr, size, type)}; if (match) { - parent.halted_watchpoint = match; - parent.jit.load()->HaltExecution(DataAbort); + m_parent.m_halted_watchpoint = match; + m_parent.m_jit->HaltExecution(DataAbort); return false; } @@ -182,32 +161,31 @@ public: } void ReturnException(u32 pc, Dynarmic::HaltReason hr) { - parent.SaveContext(parent.breakpoint_context); - parent.breakpoint_context.cpu_registers[15] = pc; - parent.jit.load()->HaltExecution(hr); - } - - bool IsInterrupted() { - return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted(); + m_parent.GetContext(m_parent.m_breakpoint_context); + m_parent.m_breakpoint_context.pc = pc; + m_parent.m_breakpoint_context.r[15] = pc; + m_parent.m_jit->HaltExecution(hr); } - ARM_Dynarmic_32& parent; - Core::Memory::Memory& memory; - std::size_t num_interpreted_instructions{}; - const bool debugger_enabled{}; - const bool check_memory_access{}; - static constexpr u64 minimum_run_cycles = 10000U; + ArmDynarmic32& m_parent; + Core::Memory::Memory& m_memory; + const Kernel::KProcess* m_process{}; + const bool m_debugger_enabled{}; + const bool m_check_memory_access{}; + static constexpr u64 MinimumRunCycles = 10000U; }; -std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const { +std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* page_table) const { Dynarmic::A32::UserConfig config; - config.callbacks = cb.get(); - config.coprocessors[15] = cp15; + config.callbacks = m_cb.get(); + config.coprocessors[15] = m_cp15; config.define_unpredictable_behaviour = true; - static constexpr std::size_t YUZU_PAGEBITS = 12; - static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - YUZU_PAGEBITS); + if (page_table) { - config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( + constexpr size_t PageBits = 12; + constexpr size_t NumPageTableEntries = 1 << (32 - PageBits); + + config.page_table = reinterpret_cast<std::array<std::uint8_t*, NumPageTableEntries>*>( page_table->pointers.data()); config.absolute_offset_page_table = true; 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* } // Multi-process state - config.processor_id = core_index; - config.global_monitor = &exclusive_monitor.monitor; + config.processor_id = m_core_index; + config.global_monitor = &m_exclusive_monitor.monitor; // Timing - config.wall_clock_cntpct = uses_wall_clock; - config.enable_cycle_counting = true; + config.wall_clock_cntpct = m_uses_wall_clock; + config.enable_cycle_counting = !m_uses_wall_clock; // Code cache size #ifdef ARCHITECTURE_arm64 @@ -236,7 +214,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* #endif // Allow memory fault handling to work - if (system.DebuggerEnabled()) { + if (m_system.DebuggerEnabled()) { config.check_halt_on_memory_access = true; } @@ -325,137 +303,140 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* return std::make_unique<Dynarmic::A32::Jit>(config); } -HaltReason ARM_Dynarmic_32::RunJit() { - return TranslateHaltReason(jit.load()->Run()); +static std::pair<u32, u32> FpscrToFpsrFpcr(u32 fpscr) { + // FPSCR bits [31:27] are mapped to FPSR[31:27]. + // FPSCR bit [7] is mapped to FPSR[7]. + // FPSCR bits [4:0] are mapped to FPSR[4:0]. + const u32 nzcv = fpscr & 0xf8000000; + const u32 idc = fpscr & 0x80; + const u32 fiq = fpscr & 0x1f; + const u32 fpsr = nzcv | idc | fiq; + + // FPSCR bits [26:15] are mapped to FPCR[26:15]. + // FPSCR bits [12:8] are mapped to FPCR[12:8]. + const u32 round = fpscr & 0x7ff8000; + const u32 trap = fpscr & 0x1f00; + const u32 fpcr = round | trap; + + return {fpsr, fpcr}; } -HaltReason ARM_Dynarmic_32::StepJit() { - return TranslateHaltReason(jit.load()->Step()); +static u32 FpsrFpcrToFpscr(u64 fpsr, u64 fpcr) { + auto [s, c] = FpscrToFpsrFpcr(static_cast<u32>(fpsr | fpcr)); + return s | c; } -u32 ARM_Dynarmic_32::GetSvcNumber() const { - return svc_swi; +bool ArmDynarmic32::IsInThumbMode() const { + return (m_jit->Cpsr() & 0x20) != 0; } -const Kernel::DebugWatchpoint* ARM_Dynarmic_32::HaltedWatchpoint() const { - return halted_watchpoint; +HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) { + m_jit->ClearExclusiveState(); + return TranslateHaltReason(m_jit->Run()); } -void ARM_Dynarmic_32::RewindBreakpointInstruction() { - LoadContext(breakpoint_context); +HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) { + m_jit->ClearExclusiveState(); + return TranslateHaltReason(m_jit->Step()); } -ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, - DynarmicExclusiveMonitor& exclusive_monitor_, - std::size_t core_index_) - : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)), - cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_}, - exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {} +u32 ArmDynarmic32::GetSvcNumber() const { + return m_svc_swi; +} -ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; +void ArmDynarmic32::GetSvcArguments(std::span<uint64_t, 8> args) const { + Dynarmic::A32::Jit& j = *m_jit; + auto& gpr = j.Regs(); -void ARM_Dynarmic_32::SetPC(u64 pc) { - jit.load()->Regs()[15] = static_cast<u32>(pc); + for (size_t i = 0; i < 8; i++) { + args[i] = gpr[i]; + } } -u64 ARM_Dynarmic_32::GetPC() const { - return jit.load()->Regs()[15]; -} +void ArmDynarmic32::SetSvcArguments(std::span<const uint64_t, 8> args) { + Dynarmic::A32::Jit& j = *m_jit; + auto& gpr = j.Regs(); -u64 ARM_Dynarmic_32::GetSP() const { - return jit.load()->Regs()[13]; + for (size_t i = 0; i < 8; i++) { + gpr[i] = static_cast<u32>(args[i]); + } } -u64 ARM_Dynarmic_32::GetReg(int index) const { - return jit.load()->Regs()[index]; +const Kernel::DebugWatchpoint* ArmDynarmic32::HaltedWatchpoint() const { + return m_halted_watchpoint; } -void ARM_Dynarmic_32::SetReg(int index, u64 value) { - jit.load()->Regs()[index] = static_cast<u32>(value); +void ArmDynarmic32::RewindBreakpointInstruction() { + this->SetContext(m_breakpoint_context); } -u128 ARM_Dynarmic_32::GetVectorReg(int index) const { - return {}; +ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process, + DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) + : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, + m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)), + m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} { + auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl(); + m_jit = MakeJit(&page_table_impl); } -void ARM_Dynarmic_32::SetVectorReg(int index, u128 value) {} +ArmDynarmic32::~ArmDynarmic32() = default; -u32 ARM_Dynarmic_32::GetPSTATE() const { - return jit.load()->Cpsr(); +void ArmDynarmic32::SetTpidrroEl0(u64 value) { + m_cp15->uro = static_cast<u32>(value); } -void ARM_Dynarmic_32::SetPSTATE(u32 cpsr) { - jit.load()->SetCpsr(cpsr); -} +void ArmDynarmic32::GetContext(Kernel::Svc::ThreadContext& ctx) const { + Dynarmic::A32::Jit& j = *m_jit; + auto& gpr = j.Regs(); + auto& fpr = j.ExtRegs(); -u64 ARM_Dynarmic_32::GetTlsAddress() const { - return cp15->uro; -} + for (size_t i = 0; i < 16; i++) { + ctx.r[i] = gpr[i]; + } -void ARM_Dynarmic_32::SetTlsAddress(u64 address) { - cp15->uro = static_cast<u32>(address); -} + ctx.fp = gpr[11]; + ctx.sp = gpr[13]; + ctx.lr = gpr[14]; + ctx.pc = gpr[15]; + ctx.pstate = j.Cpsr(); -u64 ARM_Dynarmic_32::GetTPIDR_EL0() const { - return cp15->uprw; -} + static_assert(sizeof(fpr) <= sizeof(ctx.v)); + std::memcpy(ctx.v.data(), &fpr, sizeof(fpr)); -void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { - cp15->uprw = static_cast<u32>(value); + auto [fpsr, fpcr] = FpscrToFpsrFpcr(j.Fpscr()); + ctx.fpcr = fpcr; + ctx.fpsr = fpsr; + ctx.tpidr = m_cp15->uprw; } -void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) const { - Dynarmic::A32::Jit* j = jit.load(); - ctx.cpu_registers = j->Regs(); - ctx.extension_registers = j->ExtRegs(); - ctx.cpsr = j->Cpsr(); - ctx.fpscr = j->Fpscr(); -} +void ArmDynarmic32::SetContext(const Kernel::Svc::ThreadContext& ctx) { + Dynarmic::A32::Jit& j = *m_jit; + auto& gpr = j.Regs(); + auto& fpr = j.ExtRegs(); -void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) { - Dynarmic::A32::Jit* j = jit.load(); - j->Regs() = ctx.cpu_registers; - j->ExtRegs() = ctx.extension_registers; - j->SetCpsr(ctx.cpsr); - j->SetFpscr(ctx.fpscr); -} + for (size_t i = 0; i < 16; i++) { + gpr[i] = static_cast<u32>(ctx.r[i]); + } -void ARM_Dynarmic_32::SignalInterrupt() { - jit.load()->HaltExecution(BreakLoop); -} + j.SetCpsr(ctx.pstate); -void ARM_Dynarmic_32::ClearInterrupt() { - jit.load()->ClearHalt(BreakLoop); -} + static_assert(sizeof(fpr) <= sizeof(ctx.v)); + std::memcpy(&fpr, ctx.v.data(), sizeof(fpr)); -void ARM_Dynarmic_32::ClearInstructionCache() { - jit.load()->ClearCache(); + j.SetFpscr(FpsrFpcrToFpscr(ctx.fpsr, ctx.fpcr)); + m_cp15->uprw = static_cast<u32>(ctx.tpidr); } -void ARM_Dynarmic_32::InvalidateCacheRange(u64 addr, std::size_t size) { - jit.load()->InvalidateCacheRange(static_cast<u32>(addr), size); +void ArmDynarmic32::SignalInterrupt(Kernel::KThread* thread) { + m_jit->HaltExecution(BreakLoop); } -void ARM_Dynarmic_32::ClearExclusiveState() { - jit.load()->ClearExclusiveState(); +void ArmDynarmic32::ClearInstructionCache() { + m_jit->ClearCache(); } -void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, - std::size_t new_address_space_size_in_bits) { - ThreadContext32 ctx{}; - SaveContext(ctx); - - auto key = std::make_pair(&page_table, new_address_space_size_in_bits); - auto iter = jit_cache.find(key); - if (iter != jit_cache.end()) { - jit.store(iter->second.get()); - LoadContext(ctx); - return; - } - std::shared_ptr new_jit = MakeJit(&page_table); - jit.store(new_jit.get()); - LoadContext(ctx); - jit_cache.emplace(key, std::move(new_jit)); +void ArmDynarmic32::InvalidateCacheRange(u64 addr, std::size_t size) { + m_jit->InvalidateCacheRange(static_cast<u32>(addr), size); } } // 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 @@ #pragma once -#include <atomic> -#include <memory> -#include <unordered_map> - #include <dynarmic/interface/A32/a32.h> -#include <dynarmic/interface/A64/a64.h> -#include "common/common_types.h" -#include "common/hash.h" + #include "core/arm/arm_interface.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" @@ -20,89 +14,63 @@ class Memory; namespace Core { -class CPUInterruptHandler; class DynarmicCallbacks32; class DynarmicCP15; -class DynarmicExclusiveMonitor; class System; -class ARM_Dynarmic_32 final : public ARM_Interface { +class ArmDynarmic32 final : public ArmInterface { public: - ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, - DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); - ~ARM_Dynarmic_32() override; - - void SetPC(u64 pc) override; - u64 GetPC() const override; - u64 GetSP() const override; - u64 GetReg(int index) const override; - void SetReg(int index, u64 value) override; - u128 GetVectorReg(int index) const override; - void SetVectorReg(int index, u128 value) override; - u32 GetPSTATE() const override; - void SetPSTATE(u32 pstate) override; - u64 GetTlsAddress() const override; - void SetTlsAddress(u64 address) override; - void SetTPIDR_EL0(u64 value) override; - u64 GetTPIDR_EL0() const override; - - bool IsInThumbMode() const { - return (GetPSTATE() & 0x20) != 0; - } + ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process, + DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); + ~ArmDynarmic32() override; Architecture GetArchitecture() const override { - return Architecture::Aarch32; + return Architecture::AArch32; } - void SaveContext(ThreadContext32& ctx) const override; - void SaveContext(ThreadContext64& ctx) const override {} - void LoadContext(const ThreadContext32& ctx) override; - void LoadContext(const ThreadContext64& ctx) override {} - void SignalInterrupt() override; - void ClearInterrupt() override; - void ClearExclusiveState() override; + bool IsInThumbMode() const; + + HaltReason RunThread(Kernel::KThread* thread) override; + HaltReason StepThread(Kernel::KThread* thread) override; + + void GetContext(Kernel::Svc::ThreadContext& ctx) const override; + void SetContext(const Kernel::Svc::ThreadContext& ctx) override; + void SetTpidrroEl0(u64 value) override; + + void GetSvcArguments(std::span<uint64_t, 8> args) const override; + void SetSvcArguments(std::span<const uint64_t, 8> args) override; + u32 GetSvcNumber() const override; + void SignalInterrupt(Kernel::KThread* thread) override; void ClearInstructionCache() override; void InvalidateCacheRange(u64 addr, std::size_t size) override; - void PageTableChanged(Common::PageTable& new_page_table, - std::size_t new_address_space_size_in_bits) override; protected: - HaltReason RunJit() override; - HaltReason StepJit() override; - u32 GetSvcNumber() const override; const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; void RewindBreakpointInstruction() override; private: - std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; - - static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc); - - using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; - using JitCacheType = - std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>; + System& m_system; + DynarmicExclusiveMonitor& m_exclusive_monitor; +private: friend class DynarmicCallbacks32; friend class DynarmicCP15; - std::unique_ptr<DynarmicCallbacks32> cb; - JitCacheType jit_cache; - std::shared_ptr<DynarmicCP15> cp15; - std::size_t core_index; - DynarmicExclusiveMonitor& exclusive_monitor; + std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; - std::shared_ptr<Dynarmic::A32::Jit> null_jit; + std::unique_ptr<DynarmicCallbacks32> m_cb{}; + std::shared_ptr<DynarmicCP15> m_cp15{}; + std::size_t m_core_index{}; - // A raw pointer here is fine; we never delete Jit instances. - std::atomic<Dynarmic::A32::Jit*> jit; + std::shared_ptr<Dynarmic::A32::Jit> m_jit{}; // SVC callback - u32 svc_swi{}; + u32 m_svc_swi{}; // Watchpoint info - const Kernel::DebugWatchpoint* halted_watchpoint; - ThreadContext32 breakpoint_context; + const Kernel::DebugWatchpoint* m_halted_watchpoint{}; + Kernel::Svc::ThreadContext m_breakpoint_context{}; }; } // 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <cinttypes> -#include <memory> -#include <dynarmic/interface/A64/a64.h> -#include <dynarmic/interface/A64/config.h> -#include "common/assert.h" -#include "common/literals.h" -#include "common/logging/log.h" -#include "common/page_table.h" #include "common/settings.h" #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" -#include "core/core.h" #include "core/core_timing.h" -#include "core/debugger/debugger.h" -#include "core/hardware_properties.h" #include "core/hle/kernel/k_process.h" -#include "core/hle/kernel/svc.h" -#include "core/memory.h" namespace Core { @@ -28,92 +15,92 @@ using namespace Common::Literals; class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { public: - explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_) - : parent{parent_}, memory(parent.system.ApplicationMemory()), - debugger_enabled{parent.system.DebuggerEnabled()}, - check_memory_access{debugger_enabled || - !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} + explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process) + : m_parent{parent}, m_memory(process->GetMemory()), + m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, + m_check_memory_access{m_debugger_enabled || + !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} {} u8 MemoryRead8(u64 vaddr) override { CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read); - return memory.Read8(vaddr); + return m_memory.Read8(vaddr); } u16 MemoryRead16(u64 vaddr) override { CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read); - return memory.Read16(vaddr); + return m_memory.Read16(vaddr); } u32 MemoryRead32(u64 vaddr) override { CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read); - return memory.Read32(vaddr); + return m_memory.Read32(vaddr); } u64 MemoryRead64(u64 vaddr) override { CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read); - return memory.Read64(vaddr); + return m_memory.Read64(vaddr); } Vector MemoryRead128(u64 vaddr) override { CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); - return {memory.Read64(vaddr), memory.Read64(vaddr + 8)}; + return {m_memory.Read64(vaddr), m_memory.Read64(vaddr + 8)}; } std::optional<u32> MemoryReadCode(u64 vaddr) override { - if (!memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { + if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) { return std::nullopt; } - return memory.Read32(vaddr); + return m_memory.Read32(vaddr); } void MemoryWrite8(u64 vaddr, u8 value) override { if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) { - memory.Write8(vaddr, value); + m_memory.Write8(vaddr, value); } } void MemoryWrite16(u64 vaddr, u16 value) override { if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) { - memory.Write16(vaddr, value); + m_memory.Write16(vaddr, value); } } void MemoryWrite32(u64 vaddr, u32 value) override { if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) { - memory.Write32(vaddr, value); + m_memory.Write32(vaddr, value); } } void MemoryWrite64(u64 vaddr, u64 value) override { if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) { - memory.Write64(vaddr, value); + m_memory.Write64(vaddr, value); } } void MemoryWrite128(u64 vaddr, Vector value) override { if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) { - memory.Write64(vaddr, value[0]); - memory.Write64(vaddr + 8, value[1]); + m_memory.Write64(vaddr, value[0]); + m_memory.Write64(vaddr + 8, value[1]); } } bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override { return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive8(vaddr, value, expected); + m_memory.WriteExclusive8(vaddr, value, expected); } bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override { return CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive16(vaddr, value, expected); + m_memory.WriteExclusive16(vaddr, value, expected); } bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override { return CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive32(vaddr, value, expected); + m_memory.WriteExclusive32(vaddr, value, expected); } bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override { return CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive64(vaddr, value, expected); + m_memory.WriteExclusive64(vaddr, value, expected); } bool MemoryWriteExclusive128(u64 vaddr, Vector value, Vector expected) override { return CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write) && - memory.WriteExclusive128(vaddr, value, expected); + m_memory.WriteExclusive128(vaddr, value, expected); } void InterpreterFallback(u64 pc, std::size_t num_instructions) override { - parent.LogBacktrace(); + m_parent.LogBacktrace(m_process); LOG_ERROR(Core_ARM, "Unimplemented instruction @ 0x{:X} for {} instructions (instr = {:08X})", pc, - num_instructions, memory.Read32(pc)); + num_instructions, m_memory.Read32(pc)); ReturnException(pc, PrefetchAbort); } @@ -124,11 +111,11 @@ public: static constexpr u64 ICACHE_LINE_SIZE = 64; const u64 cache_line_start = value & ~(ICACHE_LINE_SIZE - 1); - parent.system.InvalidateCpuInstructionCacheRange(cache_line_start, ICACHE_LINE_SIZE); + m_parent.InvalidateCacheRange(cache_line_start, ICACHE_LINE_SIZE); break; } case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoU: - parent.system.InvalidateCpuInstructionCaches(); + m_parent.ClearInstructionCache(); break; case Dynarmic::A64::InstructionCacheOperation::InvalidateAllToPoUInnerSharable: default: @@ -136,7 +123,7 @@ public: break; } - parent.jit.load()->HaltExecution(Dynarmic::HaltReason::CacheInvalidation); + m_parent.m_jit->HaltExecution(Dynarmic::HaltReason::CacheInvalidation); } void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override { @@ -152,26 +139,24 @@ public: ReturnException(pc, PrefetchAbort); return; default: - if (debugger_enabled) { + if (m_debugger_enabled) { ReturnException(pc, InstructionBreakpoint); return; } - parent.LogBacktrace(); + m_parent.LogBacktrace(m_process); LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", - static_cast<std::size_t>(exception), pc, memory.Read32(pc)); + static_cast<std::size_t>(exception), pc, m_memory.Read32(pc)); } } - void CallSVC(u32 swi) override { - parent.svc_swi = swi; - parent.jit.load()->HaltExecution(SupervisorCall); + void CallSVC(u32 svc) override { + m_parent.m_svc = svc; + m_parent.m_jit->HaltExecution(SupervisorCall); } void AddTicks(u64 ticks) override { - if (parent.uses_wall_clock) { - return; - } + ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled"); // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a // rough approximation of the amount of executed ticks in the system, it may be thrown off @@ -182,44 +167,39 @@ public: // Always execute at least one tick. amortized_ticks = std::max<u64>(amortized_ticks, 1); - parent.system.CoreTiming().AddTicks(amortized_ticks); + m_parent.m_system.CoreTiming().AddTicks(amortized_ticks); } u64 GetTicksRemaining() override { - if (parent.uses_wall_clock) { - if (!IsInterrupted()) { - return minimum_run_cycles; - } - return 0U; - } + ASSERT_MSG(!m_parent.m_uses_wall_clock, "Dynarmic ticking disabled"); - return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); + return std::max<s64>(m_parent.m_system.CoreTiming().GetDowncount(), 0); } u64 GetCNTPCT() override { - return parent.system.CoreTiming().GetClockTicks(); + return m_parent.m_system.CoreTiming().GetClockTicks(); } bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type) { - if (!check_memory_access) { + if (!m_check_memory_access) { return true; } - if (!memory.IsValidVirtualAddressRange(addr, size)) { + if (!m_memory.IsValidVirtualAddressRange(addr, size)) { LOG_CRITICAL(Core_ARM, "Stopping execution due to unmapped memory access at {:#x}", addr); - parent.jit.load()->HaltExecution(PrefetchAbort); + m_parent.m_jit->HaltExecution(PrefetchAbort); return false; } - if (!debugger_enabled) { + if (!m_debugger_enabled) { return true; } - const auto match{parent.MatchingWatchpoint(addr, size, type)}; + const auto match{m_parent.MatchingWatchpoint(addr, size, type)}; if (match) { - parent.halted_watchpoint = match; - parent.jit.load()->HaltExecution(DataAbort); + m_parent.m_halted_watchpoint = match; + m_parent.m_jit->HaltExecution(DataAbort); return false; } @@ -227,30 +207,27 @@ public: } void ReturnException(u64 pc, Dynarmic::HaltReason hr) { - parent.SaveContext(parent.breakpoint_context); - parent.breakpoint_context.pc = pc; - parent.jit.load()->HaltExecution(hr); + m_parent.GetContext(m_parent.m_breakpoint_context); + m_parent.m_breakpoint_context.pc = pc; + m_parent.m_jit->HaltExecution(hr); } - bool IsInterrupted() { - return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted(); - } - - ARM_Dynarmic_64& parent; - Core::Memory::Memory& memory; - u64 tpidrro_el0 = 0; - u64 tpidr_el0 = 0; - const bool debugger_enabled{}; - const bool check_memory_access{}; - static constexpr u64 minimum_run_cycles = 10000U; + ArmDynarmic64& m_parent; + Core::Memory::Memory& m_memory; + u64 m_tpidrro_el0{}; + u64 m_tpidr_el0{}; + const Kernel::KProcess* m_process{}; + const bool m_debugger_enabled{}; + const bool m_check_memory_access{}; + static constexpr u64 MinimumRunCycles = 10000U; }; -std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table, - std::size_t address_space_bits) const { +std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* page_table, + std::size_t address_space_bits) const { Dynarmic::A64::UserConfig config; // Callbacks - config.callbacks = cb.get(); + config.callbacks = m_cb.get(); // Memory if (page_table) { @@ -271,12 +248,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* } // Multi-process state - config.processor_id = core_index; - config.global_monitor = &exclusive_monitor.monitor; + config.processor_id = m_core_index; + config.global_monitor = &m_exclusive_monitor.monitor; // System registers - config.tpidrro_el0 = &cb->tpidrro_el0; - config.tpidr_el0 = &cb->tpidr_el0; + config.tpidrro_el0 = &m_cb->m_tpidrro_el0; + config.tpidr_el0 = &m_cb->m_tpidr_el0; config.dczid_el0 = 4; config.ctr_el0 = 0x8444c004; config.cntfrq_el0 = Hardware::CNTFREQ; @@ -285,8 +262,8 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* config.define_unpredictable_behaviour = true; // Timing - config.wall_clock_cntpct = uses_wall_clock; - config.enable_cycle_counting = true; + config.wall_clock_cntpct = m_uses_wall_clock; + config.enable_cycle_counting = !m_uses_wall_clock; // Code cache size #ifdef ARCHITECTURE_arm64 @@ -296,7 +273,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* #endif // Allow memory fault handling to work - if (system.DebuggerEnabled()) { + if (m_system.DebuggerEnabled()) { config.check_halt_on_memory_access = true; } @@ -384,147 +361,112 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* return std::make_shared<Dynarmic::A64::Jit>(config); } -HaltReason ARM_Dynarmic_64::RunJit() { - return TranslateHaltReason(jit.load()->Run()); -} - -HaltReason ARM_Dynarmic_64::StepJit() { - return TranslateHaltReason(jit.load()->Step()); -} - -u32 ARM_Dynarmic_64::GetSvcNumber() const { - return svc_swi; -} - -const Kernel::DebugWatchpoint* ARM_Dynarmic_64::HaltedWatchpoint() const { - return halted_watchpoint; -} - -void ARM_Dynarmic_64::RewindBreakpointInstruction() { - LoadContext(breakpoint_context); -} - -ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, - DynarmicExclusiveMonitor& exclusive_monitor_, - std::size_t core_index_) - : ARM_Interface{system_, uses_wall_clock_}, - cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_}, - exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {} - -ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; - -void ARM_Dynarmic_64::SetPC(u64 pc) { - jit.load()->SetPC(pc); -} - -u64 ARM_Dynarmic_64::GetPC() const { - return jit.load()->GetPC(); +HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) { + m_jit->ClearExclusiveState(); + return TranslateHaltReason(m_jit->Run()); } -u64 ARM_Dynarmic_64::GetSP() const { - return jit.load()->GetSP(); +HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) { + m_jit->ClearExclusiveState(); + return TranslateHaltReason(m_jit->Step()); } -u64 ARM_Dynarmic_64::GetReg(int index) const { - return jit.load()->GetRegister(index); +u32 ArmDynarmic64::GetSvcNumber() const { + return m_svc; } -void ARM_Dynarmic_64::SetReg(int index, u64 value) { - jit.load()->SetRegister(index, value); -} +void ArmDynarmic64::GetSvcArguments(std::span<uint64_t, 8> args) const { + Dynarmic::A64::Jit& j = *m_jit; -u128 ARM_Dynarmic_64::GetVectorReg(int index) const { - return jit.load()->GetVector(index); + for (size_t i = 0; i < 8; i++) { + args[i] = j.GetRegister(i); + } } -void ARM_Dynarmic_64::SetVectorReg(int index, u128 value) { - jit.load()->SetVector(index, value); -} +void ArmDynarmic64::SetSvcArguments(std::span<const uint64_t, 8> args) { + Dynarmic::A64::Jit& j = *m_jit; -u32 ARM_Dynarmic_64::GetPSTATE() const { - return jit.load()->GetPstate(); + for (size_t i = 0; i < 8; i++) { + j.SetRegister(i, args[i]); + } } -void ARM_Dynarmic_64::SetPSTATE(u32 pstate) { - jit.load()->SetPstate(pstate); +const Kernel::DebugWatchpoint* ArmDynarmic64::HaltedWatchpoint() const { + return m_halted_watchpoint; } -u64 ARM_Dynarmic_64::GetTlsAddress() const { - return cb->tpidrro_el0; +void ArmDynarmic64::RewindBreakpointInstruction() { + this->SetContext(m_breakpoint_context); } -void ARM_Dynarmic_64::SetTlsAddress(u64 address) { - cb->tpidrro_el0 = address; +ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process, + DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) + : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, + m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} { + auto& page_table = process->GetPageTable().GetBasePageTable(); + auto& page_table_impl = page_table.GetImpl(); + m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth()); } -u64 ARM_Dynarmic_64::GetTPIDR_EL0() const { - return cb->tpidr_el0; -} +ArmDynarmic64::~ArmDynarmic64() = default; -void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { - cb->tpidr_el0 = value; +void ArmDynarmic64::SetTpidrroEl0(u64 value) { + m_cb->m_tpidrro_el0 = value; } -void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) const { - Dynarmic::A64::Jit* j = jit.load(); - ctx.cpu_registers = j->GetRegisters(); - ctx.sp = j->GetSP(); - ctx.pc = j->GetPC(); - ctx.pstate = j->GetPstate(); - ctx.vector_registers = j->GetVectors(); - ctx.fpcr = j->GetFpcr(); - ctx.fpsr = j->GetFpsr(); - ctx.tpidr = cb->tpidr_el0; -} +void ArmDynarmic64::GetContext(Kernel::Svc::ThreadContext& ctx) const { + Dynarmic::A64::Jit& j = *m_jit; + auto gpr = j.GetRegisters(); + auto fpr = j.GetVectors(); -void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) { - Dynarmic::A64::Jit* j = jit.load(); - j->SetRegisters(ctx.cpu_registers); - j->SetSP(ctx.sp); - j->SetPC(ctx.pc); - j->SetPstate(ctx.pstate); - j->SetVectors(ctx.vector_registers); - j->SetFpcr(ctx.fpcr); - j->SetFpsr(ctx.fpsr); - SetTPIDR_EL0(ctx.tpidr); + // TODO: this is inconvenient + for (size_t i = 0; i < 29; i++) { + ctx.r[i] = gpr[i]; + } + ctx.fp = gpr[29]; + ctx.lr = gpr[30]; + + ctx.sp = j.GetSP(); + ctx.pc = j.GetPC(); + ctx.pstate = j.GetPstate(); + ctx.v = fpr; + ctx.fpcr = j.GetFpcr(); + ctx.fpsr = j.GetFpsr(); + ctx.tpidr = m_cb->m_tpidr_el0; } -void ARM_Dynarmic_64::SignalInterrupt() { - jit.load()->HaltExecution(BreakLoop); -} +void ArmDynarmic64::SetContext(const Kernel::Svc::ThreadContext& ctx) { + Dynarmic::A64::Jit& j = *m_jit; -void ARM_Dynarmic_64::ClearInterrupt() { - jit.load()->ClearHalt(BreakLoop); -} + // TODO: this is inconvenient + std::array<u64, 31> gpr; -void ARM_Dynarmic_64::ClearInstructionCache() { - jit.load()->ClearCache(); + for (size_t i = 0; i < 29; i++) { + gpr[i] = ctx.r[i]; + } + gpr[29] = ctx.fp; + gpr[30] = ctx.lr; + + j.SetRegisters(gpr); + j.SetSP(ctx.sp); + j.SetPC(ctx.pc); + j.SetPstate(ctx.pstate); + j.SetVectors(ctx.v); + j.SetFpcr(ctx.fpcr); + j.SetFpsr(ctx.fpsr); + m_cb->m_tpidr_el0 = ctx.tpidr; } -void ARM_Dynarmic_64::InvalidateCacheRange(u64 addr, std::size_t size) { - jit.load()->InvalidateCacheRange(addr, size); +void ArmDynarmic64::SignalInterrupt(Kernel::KThread* thread) { + m_jit->HaltExecution(BreakLoop); } -void ARM_Dynarmic_64::ClearExclusiveState() { - jit.load()->ClearExclusiveState(); +void ArmDynarmic64::ClearInstructionCache() { + m_jit->ClearCache(); } -void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, - std::size_t new_address_space_size_in_bits) { - ThreadContext64 ctx{}; - SaveContext(ctx); - - auto key = std::make_pair(&page_table, new_address_space_size_in_bits); - auto iter = jit_cache.find(key); - if (iter != jit_cache.end()) { - jit.store(iter->second.get()); - LoadContext(ctx); - return; - } - std::shared_ptr new_jit = MakeJit(&page_table, new_address_space_size_in_bits); - jit.store(new_jit.get()); - LoadContext(ctx); - jit_cache.emplace(key, std::move(new_jit)); +void ArmDynarmic64::InvalidateCacheRange(u64 addr, std::size_t size) { + m_jit->InvalidateCacheRange(addr, size); } } // 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; class DynarmicExclusiveMonitor; class System; -class ARM_Dynarmic_64 final : public ARM_Interface { +class ArmDynarmic64 final : public ArmInterface { public: - ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, - DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); - ~ARM_Dynarmic_64() override; - - void SetPC(u64 pc) override; - u64 GetPC() const override; - u64 GetSP() const override; - u64 GetReg(int index) const override; - void SetReg(int index, u64 value) override; - u128 GetVectorReg(int index) const override; - void SetVectorReg(int index, u128 value) override; - u32 GetPSTATE() const override; - void SetPSTATE(u32 pstate) override; - u64 GetTlsAddress() const override; - void SetTlsAddress(u64 address) override; - void SetTPIDR_EL0(u64 value) override; - u64 GetTPIDR_EL0() const override; + ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process, + DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); + ~ArmDynarmic64() override; Architecture GetArchitecture() const override { - return Architecture::Aarch64; + return Architecture::AArch64; } - void SaveContext(ThreadContext32& ctx) const override {} - void SaveContext(ThreadContext64& ctx) const override; - void LoadContext(const ThreadContext32& ctx) override {} - void LoadContext(const ThreadContext64& ctx) override; - void SignalInterrupt() override; - void ClearInterrupt() override; - void ClearExclusiveState() override; + HaltReason RunThread(Kernel::KThread* thread) override; + HaltReason StepThread(Kernel::KThread* thread) override; + void GetContext(Kernel::Svc::ThreadContext& ctx) const override; + void SetContext(const Kernel::Svc::ThreadContext& ctx) override; + void SetTpidrroEl0(u64 value) override; + + void GetSvcArguments(std::span<uint64_t, 8> args) const override; + void SetSvcArguments(std::span<const uint64_t, 8> args) override; + u32 GetSvcNumber() const override; + + void SignalInterrupt(Kernel::KThread* thread) override; void ClearInstructionCache() override; void InvalidateCacheRange(u64 addr, std::size_t size) override; - void PageTableChanged(Common::PageTable& new_page_table, - std::size_t new_address_space_size_in_bits) override; protected: - HaltReason RunJit() override; - HaltReason StepJit() override; - u32 GetSvcNumber() const override; const Kernel::DebugWatchpoint* HaltedWatchpoint() const override; void RewindBreakpointInstruction() override; private: - std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, - std::size_t address_space_bits) const; - - using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; - using JitCacheType = - std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>; + System& m_system; + DynarmicExclusiveMonitor& m_exclusive_monitor; +private: friend class DynarmicCallbacks64; - std::unique_ptr<DynarmicCallbacks64> cb; - JitCacheType jit_cache; - - std::size_t core_index; - DynarmicExclusiveMonitor& exclusive_monitor; - std::shared_ptr<Dynarmic::A64::Jit> null_jit; + std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, + std::size_t address_space_bits) const; + std::unique_ptr<DynarmicCallbacks64> m_cb{}; + std::size_t m_core_index{}; - // A raw pointer here is fine; we never delete Jit instances. - std::atomic<Dynarmic::A64::Jit*> jit; + std::shared_ptr<Dynarmic::A64::Jit> m_jit{}; // SVC callback - u32 svc_swi{}; + u32 m_svc{}; - // Breakpoint info - const Kernel::DebugWatchpoint* halted_watchpoint; - ThreadContext64 breakpoint_context; + // Watchpoint info + const Kernel::DebugWatchpoint* m_halted_watchpoint{}; + Kernel::Svc::ThreadContext m_breakpoint_context{}; }; } // 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 if (!two && opc == 0 && CRm == CoprocReg::C14) { // CNTPCT const auto callback = [](void* arg, u32, u32) -> u64 { - const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg); - return parent_arg.system.CoreTiming().GetClockTicks(); + const auto& parent_arg = *static_cast<ArmDynarmic32*>(arg); + return parent_arg.m_system.CoreTiming().GetClockTicks(); }; return Callback{callback, &parent}; } 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 @@ namespace Core { -class ARM_Dynarmic_32; +class ArmDynarmic32; class DynarmicCP15 final : public Dynarmic::A32::Coprocessor { public: using CoprocReg = Dynarmic::A32::CoprocReg; - explicit DynarmicCP15(ARM_Dynarmic_32& parent_) : parent{parent_} {} + explicit DynarmicCP15(ArmDynarmic32& parent_) : parent{parent_} {} std::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, CoprocReg CRn, CoprocReg CRm, @@ -32,11 +32,11 @@ public: std::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, std::optional<u8> option) override; - ARM_Dynarmic_32& parent; + ArmDynarmic32& parent; u32 uprw = 0; u32 uro = 0; - friend class ARM_Dynarmic_32; + friend class ArmDynarmic32; }; } // 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; namespace Core { -class ARM_Dynarmic_32; -class ARM_Dynarmic_64; +class ArmDynarmic32; +class ArmDynarmic64; class DynarmicExclusiveMonitor final : public ExclusiveMonitor { public: @@ -36,8 +36,8 @@ public: bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) override; private: - friend class ARM_Dynarmic_32; - friend class ARM_Dynarmic_64; + friend class ArmDynarmic32; + friend class ArmDynarmic64; Dynarmic::ExclusiveMonitor monitor; Core::Memory::Memory& memory; }; 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 @@ #include "common/signal_chain.h" #include "core/arm/nce/arm_nce.h" +#include "core/arm/nce/guest_context.h" #include "core/arm/nce/patcher.h" #include "core/core.h" #include "core/memory.h" @@ -38,7 +39,7 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) { } // namespace -void* ARM_NCE::RestoreGuestContext(void* raw_context) { +void* ArmNce::RestoreGuestContext(void* raw_context) { // Retrieve the host context. auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext; @@ -71,7 +72,7 @@ void* ARM_NCE::RestoreGuestContext(void* raw_context) { return tpidr; } -void ARM_NCE::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) { +void ArmNce::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) { // Retrieve the host context. auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext; @@ -103,7 +104,7 @@ void ARM_NCE::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) { host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0); } -bool ARM_NCE::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { +bool ArmNce::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext; auto* info = static_cast<siginfo_t*>(raw_info); @@ -134,7 +135,7 @@ bool ARM_NCE::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* ra // - If we lose the race, then SignalInterrupt will send us a signal we are masking, // and it will do nothing when it is unmasked, as we have already left guest code. // - If we win the race, then SignalInterrupt will wait for us to unlock first. - auto& thread_params = guest_ctx->parent->running_thread->GetNativeExecutionParameters(); + auto& thread_params = guest_ctx->parent->m_running_thread->GetNativeExecutionParameters(); thread_params.lock.store(SpinLockLocked); // Return to host. @@ -142,97 +143,93 @@ bool ARM_NCE::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* ra return false; } -void ARM_NCE::HandleHostFault(int sig, void* raw_info, void* raw_context) { +void ArmNce::HandleHostFault(int sig, void* raw_info, void* raw_context) { return g_orig_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context); } -HaltReason ARM_NCE::RunJit() { - // Get the thread parameters. - // TODO: pass the current thread down from ::Run - auto* thread = Kernel::GetCurrentThreadPointer(system.Kernel()); +void ArmNce::LockThread(Kernel::KThread* thread) { auto* thread_params = &thread->GetNativeExecutionParameters(); + LockThreadParameters(thread_params); +} - { - // Lock our core context. - std::scoped_lock lk{lock}; - - // We should not be running. - ASSERT(running_thread == nullptr); - - // Check if we need to run. If we have already been halted, we are done. - u64 halt = guest_ctx.esr_el1.exchange(0); - if (halt != 0) { - return static_cast<HaltReason>(halt); - } - - // Mark that we are running. - running_thread = thread; +void ArmNce::UnlockThread(Kernel::KThread* thread) { + auto* thread_params = &thread->GetNativeExecutionParameters(); + UnlockThreadParameters(thread_params); +} - // Acquire the lock on the thread parameters. - // This allows us to force synchronization with SignalInterrupt. - LockThreadParameters(thread_params); +HaltReason ArmNce::RunThread(Kernel::KThread* thread) { + // Check if we're already interrupted. + // If we are, we can just return immediately. + HaltReason hr = static_cast<HaltReason>(m_guest_ctx.esr_el1.exchange(0)); + if (True(hr)) { + return hr; } + // Get the thread context. + auto* thread_params = &thread->GetNativeExecutionParameters(); + auto* process = thread->GetOwnerProcess(); + // Assign current members. - guest_ctx.parent = this; - thread_params->native_context = &guest_ctx; - thread_params->tpidr_el0 = guest_ctx.tpidr_el0; - thread_params->tpidrro_el0 = guest_ctx.tpidrro_el0; + m_running_thread = thread; + m_guest_ctx.parent = this; + thread_params->native_context = &m_guest_ctx; + thread_params->tpidr_el0 = m_guest_ctx.tpidr_el0; + thread_params->tpidrro_el0 = m_guest_ctx.tpidrro_el0; thread_params->is_running = true; - HaltReason halt{}; - // TODO: finding and creating the post handler needs to be locked // to deal with dynamic loading of NROs. - const auto& post_handlers = system.ApplicationProcess()->GetPostHandlers(); - if (auto it = post_handlers.find(guest_ctx.pc); it != post_handlers.end()) { - halt = ReturnToRunCodeByTrampoline(thread_params, &guest_ctx, it->second); + const auto& post_handlers = process->GetPostHandlers(); + if (auto it = post_handlers.find(m_guest_ctx.pc); it != post_handlers.end()) { + hr = ReturnToRunCodeByTrampoline(thread_params, &m_guest_ctx, it->second); } else { - halt = ReturnToRunCodeByExceptionLevelChange(thread_id, thread_params); + hr = ReturnToRunCodeByExceptionLevelChange(m_thread_id, thread_params); } // Unload members. // The thread does not change, so we can persist the old reference. - guest_ctx.tpidr_el0 = thread_params->tpidr_el0; + m_running_thread = nullptr; + m_guest_ctx.tpidr_el0 = thread_params->tpidr_el0; thread_params->native_context = nullptr; thread_params->is_running = false; - // Unlock the thread parameters. - UnlockThreadParameters(thread_params); - - { - // Lock the core context. - std::scoped_lock lk{lock}; - - // On exit, we no longer have an active thread. - running_thread = nullptr; - } - // Return the halt reason. - return halt; + return hr; } -HaltReason ARM_NCE::StepJit() { +HaltReason ArmNce::StepThread(Kernel::KThread* thread) { return HaltReason::StepThread; } -u32 ARM_NCE::GetSvcNumber() const { - return guest_ctx.svc_swi; +u32 ArmNce::GetSvcNumber() const { + return m_guest_ctx.svc; +} + +void ArmNce::GetSvcArguments(std::span<uint64_t, 8> args) const { + for (size_t i = 0; i < 8; i++) { + args[i] = m_guest_ctx.cpu_registers[i]; + } +} + +void ArmNce::SetSvcArguments(std::span<const uint64_t, 8> args) { + for (size_t i = 0; i < 8; i++) { + m_guest_ctx.cpu_registers[i] = args[i]; + } } -ARM_NCE::ARM_NCE(System& system_, bool uses_wall_clock_, std::size_t core_index_) - : ARM_Interface{system_, uses_wall_clock_}, core_index{core_index_} { - guest_ctx.system = &system_; +ArmNce::ArmNce(System& system, bool uses_wall_clock, std::size_t core_index) + : ArmInterface{uses_wall_clock}, m_system{system}, m_core_index{core_index} { + m_guest_ctx.system = &m_system; } -ARM_NCE::~ARM_NCE() = default; +ArmNce::~ArmNce() = default; -void ARM_NCE::Initialize() { - thread_id = gettid(); +void ArmNce::Initialize() { + m_thread_id = gettid(); // Setup our signals - static std::once_flag flag; - std::call_once(flag, [] { + static std::once_flag signals; + std::call_once(signals, [] { using HandlerType = decltype(sigaction::sa_sigaction); sigset_t signal_mask; @@ -244,7 +241,7 @@ void ARM_NCE::Initialize() { struct sigaction return_to_run_code_action {}; return_to_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK; return_to_run_code_action.sa_sigaction = reinterpret_cast<HandlerType>( - &ARM_NCE::ReturnToRunCodeByExceptionLevelChangeSignalHandler); + &ArmNce::ReturnToRunCodeByExceptionLevelChangeSignalHandler); return_to_run_code_action.sa_mask = signal_mask; Common::SigAction(ReturnToRunCodeByExceptionLevelChangeSignal, &return_to_run_code_action, nullptr); @@ -252,14 +249,13 @@ void ARM_NCE::Initialize() { struct sigaction break_from_run_code_action {}; break_from_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK; break_from_run_code_action.sa_sigaction = - reinterpret_cast<HandlerType>(&ARM_NCE::BreakFromRunCodeSignalHandler); + reinterpret_cast<HandlerType>(&ArmNce::BreakFromRunCodeSignalHandler); break_from_run_code_action.sa_mask = signal_mask; Common::SigAction(BreakFromRunCodeSignal, &break_from_run_code_action, nullptr); struct sigaction fault_action {}; fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART; - fault_action.sa_sigaction = - reinterpret_cast<HandlerType>(&ARM_NCE::GuestFaultSignalHandler); + fault_action.sa_sigaction = reinterpret_cast<HandlerType>(&ArmNce::GuestFaultSignalHandler); fault_action.sa_mask = signal_mask; Common::SigAction(GuestFaultSignal, &fault_action, &g_orig_action); @@ -272,111 +268,59 @@ void ARM_NCE::Initialize() { }); } -void ARM_NCE::SetPC(u64 pc) { - guest_ctx.pc = pc; +void ArmNce::SetTpidrroEl0(u64 value) { + m_guest_ctx.tpidrro_el0 = value; } -u64 ARM_NCE::GetPC() const { - return guest_ctx.pc; -} - -u64 ARM_NCE::GetSP() const { - return guest_ctx.sp; -} - -u64 ARM_NCE::GetReg(int index) const { - return guest_ctx.cpu_registers[index]; -} - -void ARM_NCE::SetReg(int index, u64 value) { - guest_ctx.cpu_registers[index] = value; -} - -u128 ARM_NCE::GetVectorReg(int index) const { - return guest_ctx.vector_registers[index]; -} - -void ARM_NCE::SetVectorReg(int index, u128 value) { - guest_ctx.vector_registers[index] = value; -} - -u32 ARM_NCE::GetPSTATE() const { - return guest_ctx.pstate; -} - -void ARM_NCE::SetPSTATE(u32 pstate) { - guest_ctx.pstate = pstate; -} - -u64 ARM_NCE::GetTlsAddress() const { - return guest_ctx.tpidrro_el0; -} - -void ARM_NCE::SetTlsAddress(u64 address) { - guest_ctx.tpidrro_el0 = address; -} - -u64 ARM_NCE::GetTPIDR_EL0() const { - return guest_ctx.tpidr_el0; -} - -void ARM_NCE::SetTPIDR_EL0(u64 value) { - guest_ctx.tpidr_el0 = value; -} - -void ARM_NCE::SaveContext(ThreadContext64& ctx) const { - ctx.cpu_registers = guest_ctx.cpu_registers; - ctx.sp = guest_ctx.sp; - ctx.pc = guest_ctx.pc; - ctx.pstate = guest_ctx.pstate; - ctx.vector_registers = guest_ctx.vector_registers; - ctx.fpcr = guest_ctx.fpcr; - ctx.fpsr = guest_ctx.fpsr; - ctx.tpidr = guest_ctx.tpidr_el0; +void ArmNce::GetContext(Kernel::Svc::ThreadContext& ctx) const { + for (size_t i = 0; i < 29; i++) { + ctx.r[i] = m_guest_ctx.cpu_registers[i]; + } + ctx.fp = m_guest_ctx.cpu_registers[29]; + ctx.lr = m_guest_ctx.cpu_registers[30]; + ctx.sp = m_guest_ctx.sp; + ctx.pc = m_guest_ctx.pc; + ctx.pstate = m_guest_ctx.pstate; + ctx.v = m_guest_ctx.vector_registers; + ctx.fpcr = m_guest_ctx.fpcr; + ctx.fpsr = m_guest_ctx.fpsr; + ctx.tpidr = m_guest_ctx.tpidr_el0; } -void ARM_NCE::LoadContext(const ThreadContext64& ctx) { - guest_ctx.cpu_registers = ctx.cpu_registers; - guest_ctx.sp = ctx.sp; - guest_ctx.pc = ctx.pc; - guest_ctx.pstate = ctx.pstate; - guest_ctx.vector_registers = ctx.vector_registers; - guest_ctx.fpcr = ctx.fpcr; - guest_ctx.fpsr = ctx.fpsr; - guest_ctx.tpidr_el0 = ctx.tpidr; +void ArmNce::SetContext(const Kernel::Svc::ThreadContext& ctx) { + for (size_t i = 0; i < 29; i++) { + m_guest_ctx.cpu_registers[i] = ctx.r[i]; + } + m_guest_ctx.cpu_registers[29] = ctx.fp; + m_guest_ctx.cpu_registers[30] = ctx.lr; + m_guest_ctx.sp = ctx.sp; + m_guest_ctx.pc = ctx.pc; + m_guest_ctx.pstate = ctx.pstate; + m_guest_ctx.vector_registers = ctx.v; + m_guest_ctx.fpcr = ctx.fpcr; + m_guest_ctx.fpsr = ctx.fpsr; + m_guest_ctx.tpidr_el0 = ctx.tpidr; } -void ARM_NCE::SignalInterrupt() { - // Lock core context. - std::scoped_lock lk{lock}; - +void ArmNce::SignalInterrupt(Kernel::KThread* thread) { // Add break loop condition. - guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop)); - - // If there is no thread running, we are done. - if (running_thread == nullptr) { - return; - } + m_guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop)); // Lock the thread context. - auto* params = &running_thread->GetNativeExecutionParameters(); + auto* params = &thread->GetNativeExecutionParameters(); LockThreadParameters(params); if (params->is_running) { // We should signal to the running thread. // The running thread will unlock the thread context. - syscall(SYS_tkill, thread_id, BreakFromRunCodeSignal); + syscall(SYS_tkill, m_thread_id, BreakFromRunCodeSignal); } else { // If the thread is no longer running, we have nothing to do. UnlockThreadParameters(params); } } -void ARM_NCE::ClearInterrupt() { - guest_ctx.esr_el1 = {}; -} - -void ARM_NCE::ClearInstructionCache() { +void ArmNce::ClearInstructionCache() { // TODO: This is not possible to implement correctly on Linux because // we do not have any access to ic iallu. @@ -384,17 +328,8 @@ void ARM_NCE::ClearInstructionCache() { std::atomic_thread_fence(std::memory_order_seq_cst); } -void ARM_NCE::InvalidateCacheRange(u64 addr, std::size_t size) { +void ArmNce::InvalidateCacheRange(u64 addr, std::size_t size) { this->ClearInstructionCache(); } -void ARM_NCE::ClearExclusiveState() { - // No-op. -} - -void ARM_NCE::PageTableChanged(Common::PageTable& page_table, - std::size_t new_address_space_size_in_bits) { - // No-op. Page table is never used. -} - } // 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 @@ #pragma once -#include <atomic> -#include <memory> -#include <span> -#include <unordered_map> -#include <vector> +#include <mutex> #include "core/arm/arm_interface.h" #include "core/arm/nce/guest_context.h" @@ -20,51 +16,36 @@ namespace Core { class System; -class ARM_NCE final : public ARM_Interface { +class ArmNce final : public ArmInterface { public: - ARM_NCE(System& system_, bool uses_wall_clock_, std::size_t core_index_); - - ~ARM_NCE() override; + ArmNce(System& system, bool uses_wall_clock, std::size_t core_index); + ~ArmNce() override; void Initialize() override; - void SetPC(u64 pc) override; - u64 GetPC() const override; - u64 GetSP() const override; - u64 GetReg(int index) const override; - void SetReg(int index, u64 value) override; - u128 GetVectorReg(int index) const override; - void SetVectorReg(int index, u128 value) override; - - u32 GetPSTATE() const override; - void SetPSTATE(u32 pstate) override; - u64 GetTlsAddress() const override; - void SetTlsAddress(u64 address) override; - void SetTPIDR_EL0(u64 value) override; - u64 GetTPIDR_EL0() const override; Architecture GetArchitecture() const override { - return Architecture::Aarch64; + return Architecture::AArch64; } - void SaveContext(ThreadContext32& ctx) const override {} - void SaveContext(ThreadContext64& ctx) const override; - void LoadContext(const ThreadContext32& ctx) override {} - void LoadContext(const ThreadContext64& ctx) override; + HaltReason RunThread(Kernel::KThread* thread) override; + HaltReason StepThread(Kernel::KThread* thread) override; + + void GetContext(Kernel::Svc::ThreadContext& ctx) const override; + void SetContext(const Kernel::Svc::ThreadContext& ctx) override; + void SetTpidrroEl0(u64 value) override; - void SignalInterrupt() override; - void ClearInterrupt() override; - void ClearExclusiveState() override; + void GetSvcArguments(std::span<uint64_t, 8> args) const override; + void SetSvcArguments(std::span<const uint64_t, 8> args) override; + u32 GetSvcNumber() const override; + + void SignalInterrupt(Kernel::KThread* thread) override; void ClearInstructionCache() override; void InvalidateCacheRange(u64 addr, std::size_t size) override; - void PageTableChanged(Common::PageTable& new_page_table, - std::size_t new_address_space_size_in_bits) override; - -protected: - HaltReason RunJit() override; - HaltReason StepJit() override; - u32 GetSvcNumber() const override; + void LockThread(Kernel::KThread* thread) override; + void UnlockThread(Kernel::KThread* thread) override; +protected: const Kernel::DebugWatchpoint* HaltedWatchpoint() const override { return nullptr; } @@ -93,16 +74,15 @@ private: static void HandleHostFault(int sig, void* info, void* raw_context); public: + Core::System& m_system; + // Members set on initialization. - std::size_t core_index{}; - pid_t thread_id{-1}; + std::size_t m_core_index{}; + pid_t m_thread_id{-1}; // Core context. - GuestContext guest_ctx; - - // Thread and invalidation info. - std::mutex lock; - Kernel::KThread* running_thread{}; + GuestContext m_guest_ctx{}; + Kernel::KThread* m_running_thread{}; }; } // 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 @@ movk reg, #(((val) >> 0x10) & 0xFFFF), lsl #16 -/* static HaltReason Core::ARM_NCE::ReturnToRunCodeByTrampoline(void* tpidr, Core::GuestContext* ctx, u64 trampoline_addr) */ -.section .text._ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, "ax", %progbits -.global _ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm -.type _ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, %function -_ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm: +/* static HaltReason Core::ArmNce::ReturnToRunCodeByTrampoline(void* tpidr, Core::GuestContext* ctx, u64 trampoline_addr) */ +.section .text._ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, "ax", %progbits +.global _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm +.type _ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm, %function +_ZN4Core6ArmNce27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm: /* Back up host sp to x3. */ /* Back up host tpidr_el0 to x4. */ mov x3, sp @@ -49,11 +49,11 @@ _ZN4Core7ARM_NCE27ReturnToRunCodeByTrampolineEPvPNS_12GuestContextEm: br x2 -/* static HaltReason Core::ARM_NCE::ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr) */ -.section .text._ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv, "ax", %progbits -.global _ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv -.type _ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv, %function -_ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv: +/* static HaltReason Core::ArmNce::ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr) */ +.section .text._ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv, "ax", %progbits +.global _ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv +.type _ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv, %function +_ZN4Core6ArmNce37ReturnToRunCodeByExceptionLevelChangeEiPv: /* This jumps to the signal handler, which will restore the entire context. */ /* On entry, x0 = thread id, which is already in the right place. */ @@ -71,17 +71,17 @@ _ZN4Core7ARM_NCE37ReturnToRunCodeByExceptionLevelChangeEiPv: brk #1000 -/* static void Core::ARM_NCE::ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info, void* raw_context) */ -.section .text._ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, "ax", %progbits -.global _ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_ -.type _ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, %function -_ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_: +/* static void Core::ArmNce::ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info, void* raw_context) */ +.section .text._ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, "ax", %progbits +.global _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_ +.type _ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_, %function +_ZN4Core6ArmNce50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_: stp x29, x30, [sp, #-0x10]! mov x29, sp /* Call the context restorer with the raw context. */ mov x0, x2 - bl _ZN4Core7ARM_NCE19RestoreGuestContextEPv + bl _ZN4Core6ArmNce19RestoreGuestContextEPv /* Save the old value of tpidr_el0. */ mrs x8, tpidr_el0 @@ -92,18 +92,18 @@ _ZN4Core7ARM_NCE50ReturnToRunCodeByExceptionLevelChangeSignalHandlerEiPvS1_: msr tpidr_el0, x0 /* Unlock the context. */ - bl _ZN4Core7ARM_NCE22UnlockThreadParametersEPv + bl _ZN4Core6ArmNce22UnlockThreadParametersEPv /* Returning from here will enter the guest. */ ldp x29, x30, [sp], #0x10 ret -/* static void Core::ARM_NCE::BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context) */ -.section .text._ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_, "ax", %progbits -.global _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_ -.type _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_, %function -_ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_: +/* static void Core::ArmNce::BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context) */ +.section .text._ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_, "ax", %progbits +.global _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_ +.type _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_, %function +_ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_: /* Check to see if we have the correct TLS magic. */ mrs x8, tpidr_el0 ldr w9, [x8, #(TpidrEl0TlsMagic)] @@ -121,7 +121,7 @@ _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_: /* Tail call the restorer. */ mov x1, x2 - b _ZN4Core7ARM_NCE16SaveGuestContextEPNS_12GuestContextEPv + b _ZN4Core6ArmNce16SaveGuestContextEPNS_12GuestContextEPv /* Returning from here will enter host code. */ @@ -130,11 +130,11 @@ _ZN4Core7ARM_NCE29BreakFromRunCodeSignalHandlerEiPvS1_: ret -/* static void Core::ARM_NCE::GuestFaultSignalHandler(int sig, void* info, void* raw_context) */ -.section .text._ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_, "ax", %progbits -.global _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_ -.type _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_, %function -_ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_: +/* static void Core::ArmNce::GuestFaultSignalHandler(int sig, void* info, void* raw_context) */ +.section .text._ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, "ax", %progbits +.global _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_ +.type _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, %function +_ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_: /* Check to see if we have the correct TLS magic. */ mrs x8, tpidr_el0 ldr w9, [x8, #(TpidrEl0TlsMagic)] @@ -146,7 +146,7 @@ _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_: /* Incorrect TLS magic, so this is a host fault. */ /* Tail call the handler. */ - b _ZN4Core7ARM_NCE15HandleHostFaultEiPvS1_ + b _ZN4Core6ArmNce15HandleHostFaultEiPvS1_ 1: /* Correct TLS magic, so this is a guest fault. */ @@ -163,7 +163,7 @@ _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_: msr tpidr_el0, x3 /* Call the handler. */ - bl _ZN4Core7ARM_NCE16HandleGuestFaultEPNS_12GuestContextEPvS3_ + bl _ZN4Core6ArmNce16HandleGuestFaultEPNS_12GuestContextEPvS3_ /* If the handler returned false, we want to preserve the host tpidr_el0. */ cbz x0, 2f @@ -177,11 +177,11 @@ _ZN4Core7ARM_NCE23GuestFaultSignalHandlerEiPvS1_: ret -/* static void Core::ARM_NCE::LockThreadParameters(void* tpidr) */ -.section .text._ZN4Core7ARM_NCE20LockThreadParametersEPv, "ax", %progbits -.global _ZN4Core7ARM_NCE20LockThreadParametersEPv -.type _ZN4Core7ARM_NCE20LockThreadParametersEPv, %function -_ZN4Core7ARM_NCE20LockThreadParametersEPv: +/* static void Core::ArmNce::LockThreadParameters(void* tpidr) */ +.section .text._ZN4Core6ArmNce20LockThreadParametersEPv, "ax", %progbits +.global _ZN4Core6ArmNce20LockThreadParametersEPv +.type _ZN4Core6ArmNce20LockThreadParametersEPv, %function +_ZN4Core6ArmNce20LockThreadParametersEPv: /* Offset to lock member. */ add x0, x0, #(TpidrEl0Lock) @@ -205,11 +205,11 @@ _ZN4Core7ARM_NCE20LockThreadParametersEPv: ret -/* static void Core::ARM_NCE::UnlockThreadParameters(void* tpidr) */ -.section .text._ZN4Core7ARM_NCE22UnlockThreadParametersEPv, "ax", %progbits -.global _ZN4Core7ARM_NCE22UnlockThreadParametersEPv -.type _ZN4Core7ARM_NCE22UnlockThreadParametersEPv, %function -_ZN4Core7ARM_NCE22UnlockThreadParametersEPv: +/* static void Core::ArmNce::UnlockThreadParameters(void* tpidr) */ +.section .text._ZN4Core6ArmNce22UnlockThreadParametersEPv, "ax", %progbits +.global _ZN4Core6ArmNce22UnlockThreadParametersEPv +.type _ZN4Core6ArmNce22UnlockThreadParametersEPv, %function +_ZN4Core6ArmNce22UnlockThreadParametersEPv: /* Offset to lock member. */ add x0, x0, #(TpidrEl0Lock) 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 @@ #pragma once +#include <atomic> + #include "common/common_funcs.h" #include "common/common_types.h" #include "core/arm/arm_interface.h" @@ -10,7 +12,7 @@ namespace Core { -class ARM_NCE; +class ArmNce; class System; struct HostContext { @@ -33,9 +35,9 @@ struct GuestContext { u64 tpidr_el0{}; std::atomic<u64> esr_el1{}; u32 nzcv{}; - u32 svc_swi{}; + u32 svc{}; System* system{}; - ARM_NCE* parent{}; + ArmNce* parent{}; }; // 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) { // Store SVC number to execute when we return c.MOV(X2, svc_id); - c.STR(W2, X1, offsetof(GuestContext, svc_swi)); + c.STR(W2, X1, offsetof(GuestContext, svc)); // We are calling a SVC. Clear esr_el1 and return it. 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 @@ #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" +#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/filesystem/filesystem.h" @@ -130,8 +131,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, struct System::Impl { explicit Impl(System& system) : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{}, - cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system}, - gpu_dirty_memory_write_manager{} { + cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{}, + time_manager{system}, gpu_dirty_memory_write_manager{} { memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager); } @@ -323,7 +324,6 @@ struct System::Impl { static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); } AddGlueRegistrationForProcess(*app_loader, *main_process); - kernel.InitializeCores(); // Initialize cheat engine if (cheat_engine) { @@ -533,6 +533,7 @@ struct System::Impl { /// Service State Service::Glue::ARPManager arp_manager; + Service::Account::ProfileManager profile_manager; Service::Time::TimeManager time_manager; /// Service manager @@ -600,14 +601,6 @@ bool System::IsPaused() const { return impl->IsPaused(); } -void System::InvalidateCpuInstructionCaches() { - impl->kernel.InvalidateAllInstructionCaches(); -} - -void System::InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size) { - impl->kernel.InvalidateCpuInstructionCacheRange(addr, size); -} - void System::ShutdownMainProcess() { impl->ShutdownMainProcess(); } @@ -696,14 +689,6 @@ const TelemetrySession& System::TelemetrySession() const { return *impl->telemetry_session; } -ARM_Interface& System::CurrentArmInterface() { - return impl->kernel.CurrentPhysicalCore().ArmInterface(); -} - -const ARM_Interface& System::CurrentArmInterface() const { - return impl->kernel.CurrentPhysicalCore().ArmInterface(); -} - Kernel::PhysicalCore& System::CurrentPhysicalCore() { return impl->kernel.CurrentPhysicalCore(); } @@ -738,14 +723,6 @@ const Kernel::KProcess* System::ApplicationProcess() const { return impl->kernel.ApplicationProcess(); } -ARM_Interface& System::ArmInterface(std::size_t core_index) { - return impl->kernel.PhysicalCore(core_index).ArmInterface(); -} - -const ARM_Interface& System::ArmInterface(std::size_t core_index) const { - return impl->kernel.PhysicalCore(core_index).ArmInterface(); -} - ExclusiveMonitor& System::Monitor() { return impl->kernel.GetExclusiveMonitor(); } @@ -946,6 +923,14 @@ const Service::APM::Controller& System::GetAPMController() const { return impl->apm_controller; } +Service::Account::ProfileManager& System::GetProfileManager() { + return impl->profile_manager; +} + +const Service::Account::ProfileManager& System::GetProfileManager() const { + return impl->profile_manager; +} + Service::Time::TimeManager& System::GetTimeManager() { return impl->time_manager; } 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; namespace Service { +namespace Account { +class ProfileManager; +} // namespace Account + namespace AM::Applets { struct AppletFrontendSet; class AppletManager; @@ -108,7 +112,6 @@ class RenderdocAPI; namespace Core { -class ARM_Interface; class CpuManager; class Debugger; class DeviceMemory; @@ -171,15 +174,6 @@ public: /// Check if the core is currently paused. [[nodiscard]] bool IsPaused() const; - /** - * Invalidate the CPU instruction caches - * This function should only be used by GDB Stub to support breakpoints, memory updates and - * step/continue commands. - */ - void InvalidateCpuInstructionCaches(); - - void InvalidateCpuInstructionCacheRange(u64 addr, std::size_t size); - /// Shutdown the main emulated process. void ShutdownMainProcess(); @@ -244,24 +238,12 @@ public: /// Gets and resets core performance statistics [[nodiscard]] PerfStatsResults GetAndResetPerfStats(); - /// Gets an ARM interface to the CPU core that is currently running - [[nodiscard]] ARM_Interface& CurrentArmInterface(); - - /// Gets an ARM interface to the CPU core that is currently running - [[nodiscard]] const ARM_Interface& CurrentArmInterface() const; - /// Gets the physical core for the CPU core that is currently running [[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore(); /// Gets the physical core for the CPU core that is currently running [[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const; - /// Gets a reference to an ARM interface for the CPU core with the specified index - [[nodiscard]] ARM_Interface& ArmInterface(std::size_t core_index); - - /// Gets a const reference to an ARM interface from the CPU core with the specified index - [[nodiscard]] const ARM_Interface& ArmInterface(std::size_t core_index) const; - /// Gets a reference to the underlying CPU manager. [[nodiscard]] CpuManager& GetCpuManager(); @@ -405,6 +387,9 @@ public: [[nodiscard]] Service::APM::Controller& GetAPMController(); [[nodiscard]] const Service::APM::Controller& GetAPMController() const; + [[nodiscard]] Service::Account::ProfileManager& GetProfileManager(); + [[nodiscard]] const Service::Account::ProfileManager& GetProfileManager() const; + [[nodiscard]] Service::Time::TimeManager& GetTimeManager(); [[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const; 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() { void CpuManager::MultiCoreRunGuestThread() { // Similar to UserModeThreadStarter in HOS auto& kernel = system.Kernel(); + auto* thread = Kernel::GetCurrentThreadPointer(kernel); kernel.CurrentScheduler()->OnThreadStart(); while (true) { auto* physical_core = &kernel.CurrentPhysicalCore(); while (!physical_core->IsInterrupted()) { - physical_core->Run(); + physical_core->RunThread(thread); physical_core = &kernel.CurrentPhysicalCore(); } @@ -110,12 +111,13 @@ void CpuManager::MultiCoreRunIdleThread() { void CpuManager::SingleCoreRunGuestThread() { auto& kernel = system.Kernel(); + auto* thread = Kernel::GetCurrentThreadPointer(kernel); kernel.CurrentScheduler()->OnThreadStart(); while (true) { auto* physical_core = &kernel.CurrentPhysicalCore(); if (!physical_core->IsInterrupted()) { - physical_core->Run(); + physical_core->RunThread(thread); physical_core = &kernel.CurrentPhysicalCore(); } @@ -211,8 +213,6 @@ void CpuManager::RunThread(std::stop_token token, std::size_t core) { system.GPU().ObtainContext(); } - system.ArmInterface(core).Initialize(); - auto& kernel = system.Kernel(); auto& scheduler = *kernel.CurrentScheduler(); 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 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/arm/arm_interface.h" +#include "core/arm/debug.h" #include "core/core.h" #include "core/debugger/gdbstub.h" #include "core/debugger/gdbstub_arch.h" @@ -310,7 +311,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction const auto mem{Common::HexStringToVector(mem_substr, false)}; if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { - system.InvalidateCpuInstructionCacheRange(addr, size); + Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size); SendReply(GDB_STUB_REPLY_OK); } else { SendReply(GDB_STUB_REPLY_ERR); @@ -363,7 +364,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { case BreakpointType::Software: replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); - system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); + Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); success = true; break; case BreakpointType::WriteWatch: @@ -411,7 +412,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { const auto orig_insn{replaced_instructions.find(addr)}; if (orig_insn != replaced_instructions.end()) { system.ApplicationMemory().Write32(addr, orig_insn->second); - system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32)); + Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); replaced_instructions.erase(addr); success = true; } @@ -442,114 +443,6 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { } } -// Structure offsets are from Atmosphere -// See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp - -static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory, - const Kernel::KThread& thread) { - // Read thread type from TLS - const VAddr tls_thread_type{memory.Read32(thread.GetTlsAddress() + 0x1fc)}; - const VAddr argument_thread_type{thread.GetArgument()}; - - if (argument_thread_type && tls_thread_type != argument_thread_type) { - // Probably not created by nnsdk, no name available. - return std::nullopt; - } - - if (!tls_thread_type) { - return std::nullopt; - } - - const u16 version{memory.Read16(tls_thread_type + 0x26)}; - VAddr name_pointer{}; - if (version == 1) { - name_pointer = memory.Read32(tls_thread_type + 0xe4); - } else { - name_pointer = memory.Read32(tls_thread_type + 0xe8); - } - - if (!name_pointer) { - // No name provided. - return std::nullopt; - } - - return memory.ReadCString(name_pointer, 256); -} - -static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory, - const Kernel::KThread& thread) { - // Read thread type from TLS - const VAddr tls_thread_type{memory.Read64(thread.GetTlsAddress() + 0x1f8)}; - const VAddr argument_thread_type{thread.GetArgument()}; - - if (argument_thread_type && tls_thread_type != argument_thread_type) { - // Probably not created by nnsdk, no name available. - return std::nullopt; - } - - if (!tls_thread_type) { - return std::nullopt; - } - - const u16 version{memory.Read16(tls_thread_type + 0x46)}; - VAddr name_pointer{}; - if (version == 1) { - name_pointer = memory.Read64(tls_thread_type + 0x1a0); - } else { - name_pointer = memory.Read64(tls_thread_type + 0x1a8); - } - - if (!name_pointer) { - // No name provided. - return std::nullopt; - } - - return memory.ReadCString(name_pointer, 256); -} - -static std::optional<std::string> GetThreadName(Core::System& system, - const Kernel::KThread& thread) { - if (system.ApplicationProcess()->Is64Bit()) { - return GetNameFromThreadType64(system.ApplicationMemory(), thread); - } else { - return GetNameFromThreadType32(system.ApplicationMemory(), thread); - } -} - -static std::string_view GetThreadWaitReason(const Kernel::KThread& thread) { - switch (thread.GetWaitReasonForDebugging()) { - case Kernel::ThreadWaitReasonForDebugging::Sleep: - return "Sleep"; - case Kernel::ThreadWaitReasonForDebugging::IPC: - return "IPC"; - case Kernel::ThreadWaitReasonForDebugging::Synchronization: - return "Synchronization"; - case Kernel::ThreadWaitReasonForDebugging::ConditionVar: - return "ConditionVar"; - case Kernel::ThreadWaitReasonForDebugging::Arbitration: - return "Arbitration"; - case Kernel::ThreadWaitReasonForDebugging::Suspended: - return "Suspended"; - default: - return "Unknown"; - } -} - -static std::string GetThreadState(const Kernel::KThread& thread) { - switch (thread.GetState()) { - case Kernel::ThreadState::Initialized: - return "Initialized"; - case Kernel::ThreadState::Waiting: - return fmt::format("Waiting ({})", GetThreadWaitReason(thread)); - case Kernel::ThreadState::Runnable: - return "Runnable"; - case Kernel::ThreadState::Terminated: - return "Terminated"; - default: - return "Unknown"; - } -} - static std::string PaginateBuffer(std::string_view buffer, std::string_view request) { const auto amount{request.substr(request.find(',') + 1)}; 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 } } -static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) { - Kernel::KMemoryInfo mem_info; - Kernel::Svc::MemoryInfo svc_mem_info; - Kernel::Svc::PageInfo page_info; - VAddr cur_addr{base}; - - // Expect: r-x Code (.text) - R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); - svc_mem_info = mem_info.GetSvcMemoryInfo(); - cur_addr = svc_mem_info.base_address + svc_mem_info.size; - if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || - svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) { - return cur_addr - 1; - } - - // Expect: r-- Code (.rodata) - R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); - svc_mem_info = mem_info.GetSvcMemoryInfo(); - cur_addr = svc_mem_info.base_address + svc_mem_info.size; - if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || - svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) { - return cur_addr - 1; - } - - // Expect: rw- CodeData (.data) - R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); - svc_mem_info = mem_info.GetSvcMemoryInfo(); - cur_addr = svc_mem_info.base_address + svc_mem_info.size; - return cur_addr - 1; -} - -static Loader::AppLoader::Modules FindModules(Core::System& system) { - Loader::AppLoader::Modules modules; - - auto& page_table = system.ApplicationProcess()->GetPageTable(); - auto& memory = system.ApplicationMemory(); - VAddr cur_addr = 0; - - // Look for executable sections in Code or AliasCode regions. - while (true) { - Kernel::KMemoryInfo mem_info{}; - Kernel::Svc::PageInfo page_info{}; - R_ASSERT( - page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); - auto svc_mem_info = mem_info.GetSvcMemoryInfo(); - - if (svc_mem_info.permission == Kernel::Svc::MemoryPermission::ReadExecute && - (svc_mem_info.state == Kernel::Svc::MemoryState::Code || - svc_mem_info.state == Kernel::Svc::MemoryState::AliasCode)) { - // Try to read the module name from its path. - constexpr s32 PathLengthMax = 0x200; - struct { - u32 zero; - s32 path_length; - std::array<char, PathLengthMax> path; - } module_path; - - if (memory.ReadBlock(svc_mem_info.base_address + svc_mem_info.size, &module_path, - sizeof(module_path))) { - if (module_path.zero == 0 && module_path.path_length > 0) { - // Truncate module name. - module_path.path[PathLengthMax - 1] = '\0'; - - // Ignore leading directories. - char* path_pointer = module_path.path.data(); - - for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) && - module_path.path[i] != '\0'; - i++) { - if (module_path.path[i] == '/' || module_path.path[i] == '\\') { - path_pointer = module_path.path.data() + i + 1; - } - } - - // Insert output. - modules.emplace(svc_mem_info.base_address, path_pointer); - } - } - } - - // Check if we're done. - const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size; - if (next_address <= cur_addr) { - break; - } - - cur_addr = next_address; - } - - return modules; -} - -static VAddr FindMainModuleEntrypoint(Core::System& system) { - Loader::AppLoader::Modules modules; - system.GetAppLoader().ReadNSOModules(modules); - - // Do we have a module named main? - const auto main = std::find_if(modules.begin(), modules.end(), - [](const auto& key) { return key.second == "main"; }); - - if (main != modules.end()) { - return main->first; - } - - // Do we have any loaded executable sections? - modules = FindModules(system); - if (!modules.empty()) { - return modules.begin()->first; - } - - // As a last resort, use the start of the code region. - return GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart()); -} - void GDBStub::HandleQuery(std::string_view command) { if (command.starts_with("TStatus")) { // no tracepoint support @@ -687,10 +466,10 @@ void GDBStub::HandleQuery(std::string_view command) { const auto target_xml{arch->GetTargetXML()}; SendReply(PaginateBuffer(target_xml, command.substr(30))); } else if (command.starts_with("Offsets")) { - const auto main_offset = FindMainModuleEntrypoint(system); - SendReply(fmt::format("TextSeg={:x}", main_offset)); + const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess()); + SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); } else if (command.starts_with("Xfer:libraries:read::")) { - auto modules = FindModules(system); + auto modules = Core::FindModules(system.ApplicationProcess()); std::string buffer; buffer += R"(<?xml version="1.0"?>)"; @@ -720,14 +499,14 @@ void GDBStub::HandleQuery(std::string_view command) { const auto& threads = system.ApplicationProcess()->GetThreadList(); for (const auto& thread : threads) { - auto thread_name{GetThreadName(system, thread)}; + auto thread_name{Core::GetThreadName(&thread)}; if (!thread_name) { thread_name = fmt::format("Thread {:d}", thread.GetThreadId()); } buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)", thread.GetThreadId(), thread.GetActiveCore(), - EscapeXML(*thread_name), GetThreadState(thread)); + EscapeXML(*thread_name), GetThreadState(&thread)); } buffer += "</threads>"; @@ -856,7 +635,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { reply = "Fastmem is not enabled.\n"; } } else if (command_str == "get info") { - auto modules = FindModules(system); + auto modules = Core::FindModules(process); reply = fmt::format("Process: {:#x} ({})\n" "Program Id: {:#018x}\n", @@ -880,7 +659,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { for (const auto& [vaddr, name] : modules) { reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, - GetModuleEnd(page_table, vaddr), name); + GetInteger(Core::GetModuleEnd(process, vaddr)), name); } } else if (command_str == "get mappings") { 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) { return Common::HexToString(mem); } -template <typename T> -static T GetSIMDRegister(const std::array<u32, 64>& simd_regs, size_t offset) { - static_assert(std::is_trivially_copyable_v<T>); - T value{}; - std::memcpy(&value, reinterpret_cast<const u8*>(simd_regs.data()) + sizeof(T) * offset, - sizeof(T)); - return value; -} - -template <typename T> -static void PutSIMDRegister(std::array<u32, 64>& simd_regs, size_t offset, const T value) { - static_assert(std::is_trivially_copyable_v<T>); - std::memcpy(reinterpret_cast<u8*>(simd_regs.data()) + sizeof(T) * offset, &value, sizeof(T)); -} - // For sample XML files see the GDB source /gdb/features // This XML defines what the registers are for this specific ARM device std::string_view GDBStubA64::GetTargetXML() const { @@ -184,12 +169,16 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const return ""; } - const auto& context{thread->GetContext64()}; - const auto& gprs{context.cpu_registers}; - const auto& fprs{context.vector_registers}; + const auto& context{thread->GetContext()}; + const auto& gprs{context.r}; + const auto& fprs{context.v}; - if (id < SP_REGISTER) { + if (id < FP_REGISTER) { return ValueToHex(gprs[id]); + } else if (id == FP_REGISTER) { + return ValueToHex(context.fp); + } else if (id == LR_REGISTER) { + return ValueToHex(context.lr); } else if (id == SP_REGISTER) { return ValueToHex(context.sp); } else if (id == PC_REGISTER) { @@ -212,10 +201,14 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v return; } - auto& context{thread->GetContext64()}; + auto& context{thread->GetContext()}; - if (id < SP_REGISTER) { - context.cpu_registers[id] = HexToValue<u64>(value); + if (id < FP_REGISTER) { + context.r[id] = HexToValue<u64>(value); + } else if (id == FP_REGISTER) { + context.fp = HexToValue<u64>(value); + } else if (id == LR_REGISTER) { + context.lr = HexToValue<u64>(value); } else if (id == SP_REGISTER) { context.sp = HexToValue<u64>(value); } else if (id == PC_REGISTER) { @@ -223,7 +216,7 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v } else if (id == PSTATE_REGISTER) { context.pstate = HexToValue<u32>(value); } else if (id >= Q0_REGISTER && id < FPSR_REGISTER) { - context.vector_registers[id - Q0_REGISTER] = HexToValue<u128>(value); + context.v[id - Q0_REGISTER] = HexToValue<u128>(value); } else if (id == FPSR_REGISTER) { context.fpsr = HexToValue<u32>(value); } else if (id == FPCR_REGISTER) { @@ -381,22 +374,20 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const return ""; } - const auto& context{thread->GetContext32()}; - const auto& gprs{context.cpu_registers}; - const auto& fprs{context.extension_registers}; + const auto& context{thread->GetContext()}; + const auto& gprs{context.r}; + const auto& fprs{context.v}; if (id <= PC_REGISTER) { - return ValueToHex(gprs[id]); + return ValueToHex(static_cast<u32>(gprs[id])); } else if (id == CPSR_REGISTER) { - return ValueToHex(context.cpsr); + return ValueToHex(context.pstate); } else if (id >= D0_REGISTER && id < Q0_REGISTER) { - const u64 dN{GetSIMDRegister<u64>(fprs, id - D0_REGISTER)}; - return ValueToHex(dN); + return ValueToHex(fprs[id - D0_REGISTER][0]); } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { - const u128 qN{GetSIMDRegister<u128>(fprs, id - Q0_REGISTER)}; - return ValueToHex(qN); + return ValueToHex(fprs[id - Q0_REGISTER]); } else if (id == FPSCR_REGISTER) { - return ValueToHex(context.fpscr); + return ValueToHex(context.fpcr | context.fpsr); } else { return ""; } @@ -407,19 +398,20 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v return; } - auto& context{thread->GetContext32()}; - auto& fprs{context.extension_registers}; + auto& context{thread->GetContext()}; + auto& fprs{context.v}; if (id <= PC_REGISTER) { - context.cpu_registers[id] = HexToValue<u32>(value); + context.r[id] = HexToValue<u32>(value); } else if (id == CPSR_REGISTER) { - context.cpsr = HexToValue<u32>(value); + context.pstate = HexToValue<u32>(value); } else if (id >= D0_REGISTER && id < Q0_REGISTER) { - PutSIMDRegister(fprs, id - D0_REGISTER, HexToValue<u64>(value)); + fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0}; } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { - PutSIMDRegister(fprs, id - Q0_REGISTER, HexToValue<u128>(value)); + fprs[id - Q0_REGISTER] = HexToValue<u128>(value); } else if (id == FPSCR_REGISTER) { - context.fpscr = HexToValue<u32>(value); + context.fpcr = HexToValue<u32>(value); + context.fpsr = HexToValue<u32>(value); } } 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: u32 BreakpointInstruction() const override; private: + static constexpr u32 FP_REGISTER = 29; static constexpr u32 LR_REGISTER = 30; static constexpr u32 SP_REGISTER = 31; 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 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <cstring> +#include <span> #include <string_view> #include "common/alignment.h" #include "common/assert.h" @@ -134,7 +135,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir, child->size = child->source->GetSize(); - AddFile(parent, child); + AddFile(parent, std::move(child)); } for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) { @@ -163,36 +164,24 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir, bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { - // Check whether it's already in the known directories. - const auto [it, is_new] = directories.emplace(dir_ctx->path, nullptr); - if (!is_new) { - return false; - } - // Add a new directory. num_dirs++; dir_table_size += sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); - dir_ctx->parent = parent_dir_ctx; - it->second = dir_ctx; + dir_ctx->parent = std::move(parent_dir_ctx); + directories.emplace_back(std::move(dir_ctx)); return true; } bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, std::shared_ptr<RomFSBuildFileContext> file_ctx) { - // Check whether it's already in the known files. - const auto [it, is_new] = files.emplace(file_ctx->path, nullptr); - if (!is_new) { - return false; - } - // Add a new file. num_files++; file_table_size += sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); - file_ctx->parent = parent_dir_ctx; - it->second = file_ctx; + file_ctx->parent = std::move(parent_dir_ctx); + files.emplace_back(std::move(file_ctx)); return true; } @@ -201,7 +190,7 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_) : base(std::move(base_)), ext(std::move(ext_)) { root = std::make_shared<RomFSBuildDirectoryContext>(); root->path = "\0"; - directories.emplace(root->path, root); + directories.emplace_back(root); num_dirs = 1; dir_table_size = 0x18; @@ -210,28 +199,43 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_) RomFSBuildContext::~RomFSBuildContext() = default; -std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { +std::vector<std::pair<u64, VirtualFile>> RomFSBuildContext::Build() { const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); dir_hash_table_size = 4 * dir_hash_table_entry_count; file_hash_table_size = 4 * file_hash_table_entry_count; - // Assign metadata pointers + // Assign metadata pointers. RomFSHeader header{}; - std::vector<u32> dir_hash_table(dir_hash_table_entry_count, ROMFS_ENTRY_EMPTY); - std::vector<u32> file_hash_table(file_hash_table_entry_count, ROMFS_ENTRY_EMPTY); - - std::vector<u8> dir_table(dir_table_size); - std::vector<u8> file_table(file_table_size); - - std::shared_ptr<RomFSBuildFileContext> cur_file; + std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + + dir_table_size); + u32* const dir_hash_table_pointer = reinterpret_cast<u32*>(metadata.data()); + u8* const dir_table_pointer = metadata.data() + dir_hash_table_size; + u32* const file_hash_table_pointer = + reinterpret_cast<u32*>(metadata.data() + dir_hash_table_size + dir_table_size); + u8* const file_table_pointer = + metadata.data() + dir_hash_table_size + dir_table_size + file_hash_table_size; + + std::span<u32> dir_hash_table(dir_hash_table_pointer, dir_hash_table_entry_count); + std::span<u32> file_hash_table(file_hash_table_pointer, file_hash_table_entry_count); + std::span<u8> dir_table(dir_table_pointer, dir_table_size); + std::span<u8> file_table(file_table_pointer, file_table_size); + + // Initialize hash tables. + std::memset(dir_hash_table.data(), 0xFF, dir_hash_table.size_bytes()); + std::memset(file_hash_table.data(), 0xFF, file_hash_table.size_bytes()); + + // Sort tables by name. + std::sort(files.begin(), files.end(), + [](const auto& a, const auto& b) { return a->path < b->path; }); + std::sort(directories.begin(), directories.end(), + [](const auto& a, const auto& b) { return a->path < b->path; }); // Determine file offsets. u32 entry_offset = 0; std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; - for (const auto& it : files) { - cur_file = it.second; + for (const auto& cur_file : files) { file_partition_size = Common::AlignUp(file_partition_size, 16); cur_file->offset = file_partition_size; file_partition_size += cur_file->size; @@ -243,34 +247,48 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { } // Assign deferred parent/sibling ownership. for (auto it = files.rbegin(); it != files.rend(); ++it) { - cur_file = it->second; + auto& cur_file = *it; cur_file->sibling = cur_file->parent->file; cur_file->parent->file = cur_file; } - std::shared_ptr<RomFSBuildDirectoryContext> cur_dir; - // Determine directory offsets. entry_offset = 0; - for (const auto& it : directories) { - cur_dir = it.second; + for (const auto& cur_dir : directories) { cur_dir->entry_offset = entry_offset; entry_offset += static_cast<u32>(sizeof(RomFSDirectoryEntry) + Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4)); } // Assign deferred parent/sibling ownership. - for (auto it = directories.rbegin(); it->second != root; ++it) { - cur_dir = it->second; + for (auto it = directories.rbegin(); (*it) != root; ++it) { + auto& cur_dir = *it; cur_dir->sibling = cur_dir->parent->child; cur_dir->parent->child = cur_dir; } - std::multimap<u64, VirtualFile> out; + // Create output map. + std::vector<std::pair<u64, VirtualFile>> out; + out.reserve(num_files + 2); + + // Set header fields. + header.header_size = sizeof(RomFSHeader); + header.file_hash_table_size = file_hash_table_size; + header.file_table_size = file_table_size; + header.dir_hash_table_size = dir_hash_table_size; + header.dir_table_size = dir_table_size; + header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; + header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4); + header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; + header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; + header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; + + std::vector<u8> header_data(sizeof(RomFSHeader)); + std::memcpy(header_data.data(), &header, header_data.size()); + out.emplace_back(0, std::make_shared<VectorVfsFile>(std::move(header_data))); // Populate file tables. - for (const auto& it : files) { - cur_file = it.second; + for (const auto& cur_file : files) { RomFSFileEntry cur_entry{}; cur_entry.parent = cur_file->parent->entry_offset; @@ -287,7 +305,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { cur_entry.name_size = name_size; - out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source)); + out.emplace_back(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source)); std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, Common::AlignUp(cur_entry.name_size, 4)); @@ -296,8 +314,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { } // Populate dir tables. - for (const auto& it : directories) { - cur_dir = it.second; + for (const auto& cur_dir : directories) { RomFSDirectoryEntry cur_entry{}; cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset; @@ -323,34 +340,13 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); } - // Set header fields. - header.header_size = sizeof(RomFSHeader); - header.file_hash_table_size = file_hash_table_size; - header.file_table_size = file_table_size; - header.dir_hash_table_size = dir_hash_table_size; - header.dir_table_size = dir_table_size; - header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; - header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4); - header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; - header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; - header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; - - std::vector<u8> header_data(sizeof(RomFSHeader)); - std::memcpy(header_data.data(), &header, header_data.size()); - out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data))); + // Write metadata. + out.emplace_back(header.dir_hash_table_ofs, + std::make_shared<VectorVfsFile>(std::move(metadata))); - std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + - dir_table_size); - std::size_t index = 0; - std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); - index += dir_hash_table.size() * sizeof(u32); - std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); - index += dir_table.size(); - std::memcpy(metadata.data() + index, file_hash_table.data(), - file_hash_table.size() * sizeof(u32)); - index += file_hash_table.size() * sizeof(u32); - std::memcpy(metadata.data() + index, file_table.data(), file_table.size()); - out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata))); + // Sort the output. + std::sort(out.begin(), out.end(), + [](const auto& a, const auto& b) { return a.first < b.first; }); return out; } 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: ~RomFSBuildContext(); // This finalizes the context. - std::multimap<u64, VirtualFile> Build(); + std::vector<std::pair<u64, VirtualFile>> Build(); private: VirtualDir base; VirtualDir ext; std::shared_ptr<RomFSBuildDirectoryContext> root; - std::map<std::string, std::shared_ptr<RomFSBuildDirectoryContext>, std::less<>> directories; - std::map<std::string, std::shared_ptr<RomFSBuildFileContext>, std::less<>> files; + std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> directories; + std::vector<std::shared_ptr<RomFSBuildFileContext>> files; u64 num_dirs = 0; u64 num_files = 0; 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 { }; static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); -template <typename Entry> -std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) { - Entry entry{}; - if (file->ReadObject(&entry, offset) != sizeof(Entry)) - return {}; - std::string string(entry.name_length, '\0'); - if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size()) +struct RomFSTraversalContext { + RomFSHeader header; + VirtualFile file; + std::vector<u8> directory_meta; + std::vector<u8> file_meta; +}; + +template <typename EntryType, auto Member> +std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, size_t offset) { + const size_t entry_end = offset + sizeof(EntryType); + const std::vector<u8>& vec = ctx.*Member; + const size_t size = vec.size(); + const u8* data = vec.data(); + EntryType entry{}; + + if (entry_end > size) { return {}; - return {entry, string}; + } + std::memcpy(&entry, data + offset, sizeof(EntryType)); + + const size_t name_length = std::min(entry_end + entry.name_length, size) - entry_end; + std::string name(reinterpret_cast<const char*>(data + entry_end), name_length); + + return {entry, std::move(name)}; +} + +std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx, + size_t directory_offset) { + return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset); +} + +std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx, + size_t file_offset) { + return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset); } -void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset, - u32 this_file_offset, std::shared_ptr<VectorVfsDirectory>& parent) { +void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset, + std::shared_ptr<VectorVfsDirectory>& parent) { while (this_file_offset != ROMFS_ENTRY_EMPTY) { - auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); + auto entry = GetFileEntry(ctx, this_file_offset); - parent->AddFile(std::make_shared<OffsetVfsFile>( - file, entry.first.size, entry.first.offset + data_offset, entry.second)); + parent->AddFile(std::make_shared<OffsetVfsFile>(ctx.file, entry.first.size, + entry.first.offset + ctx.header.data_offset, + std::move(entry.second))); this_file_offset = entry.first.sibling; } } -void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset, - std::size_t data_offset, u32 this_dir_offset, +void ProcessDirectory(const RomFSTraversalContext& ctx, u32 this_dir_offset, std::shared_ptr<VectorVfsDirectory>& parent) { while (this_dir_offset != ROMFS_ENTRY_EMPTY) { - auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); + auto entry = GetDirectoryEntry(ctx, this_dir_offset); auto current = std::make_shared<VectorVfsDirectory>( std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); if (entry.first.child_file != ROMFS_ENTRY_EMPTY) { - ProcessFile(file, file_offset, data_offset, entry.first.child_file, current); + ProcessFile(ctx, entry.first.child_file, current); } if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) { - ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir, - current); + ProcessDirectory(ctx, entry.first.child_dir, current); } parent->AddDirectory(current); @@ -107,22 +131,25 @@ VirtualDir ExtractRomFS(VirtualFile file) { return root_container; } - RomFSHeader header{}; - if (file->ReadObject(&header) != sizeof(RomFSHeader)) { - return root_container; + RomFSTraversalContext ctx{}; + + if (file->ReadObject(&ctx.header) != sizeof(RomFSHeader)) { + return nullptr; } - if (header.header_size != sizeof(RomFSHeader)) { - return root_container; + if (ctx.header.header_size != sizeof(RomFSHeader)) { + return nullptr; } - const u64 file_offset = header.file_meta.offset; - const u64 dir_offset = header.directory_meta.offset; + ctx.file = file; + ctx.directory_meta = + file->ReadBytes(ctx.header.directory_meta.size, ctx.header.directory_meta.offset); + ctx.file_meta = file->ReadBytes(ctx.header.file_meta.size, ctx.header.file_meta.offset); - ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container); + ProcessDirectory(ctx, 0, root_container); if (auto root = root_container->GetSubdirectory(""); root) { - return std::make_shared<CachedVfsDirectory>(std::move(root)); + return root; } 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 @@ namespace FileSys { -constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size"; - namespace { void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) { @@ -197,7 +195,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id, GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); - const auto size_file = relative_dir->GetFile(SAVE_DATA_SIZE_FILENAME); + const auto size_file = relative_dir->GetFile(GetSaveDataSizeFileName()); if (size_file == nullptr || size_file->GetSize() < sizeof(SaveDataSize)) { return {0, 0}; } @@ -216,7 +214,7 @@ void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 us GetFullPath(system, dir, SaveDataSpaceId::NandUser, type, title_id, user_id, 0); const auto relative_dir = GetOrCreateDirectoryRelative(dir, path); - const auto size_file = relative_dir->CreateFile(SAVE_DATA_SIZE_FILENAME); + const auto size_file = relative_dir->CreateFile(GetSaveDataSizeFileName()); if (size_file == nullptr) { return; } 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 { u64 journal; }; +constexpr const char* GetSaveDataSizeFileName() { + return ".yuzu_save_size"; +} + /// File system interface to the SaveData archive class SaveDataFactory { public: 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, return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map))); } -VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::string&& name, - std::multimap<u64, VirtualFile>&& files) { +VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile( + u8 filler_byte, std::string&& name, std::vector<std::pair<u64, VirtualFile>>&& files) { // Fold trivial cases. if (files.empty()) { 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: /// Convenience function that turns a map of offsets to files into a concatenated file, filling /// gaps with a given filler byte. static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name, - std::multimap<u64, VirtualFile>&& files); + std::vector<std::pair<u64, VirtualFile>>&& files); std::string GetName() const override; 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 @@ #include <algorithm> #include <set> +#include <unordered_set> #include <utility> #include "core/file_sys/vfs_layered.h" @@ -59,13 +60,12 @@ std::string LayeredVfsDirectory::GetFullPath() const { std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { std::vector<VirtualFile> out; - std::set<std::string, std::less<>> out_names; + std::unordered_set<std::string> out_names; for (const auto& layer : dirs) { for (auto& file : layer->GetFiles()) { - auto file_name = file->GetName(); - if (!out_names.contains(file_name)) { - out_names.emplace(std::move(file_name)); + const auto [it, is_new] = out_names.emplace(file->GetName()); + if (is_new) { out.emplace_back(std::move(file)); } } @@ -75,18 +75,19 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { } std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const { - std::vector<std::string> names; + std::vector<VirtualDir> out; + std::unordered_set<std::string> out_names; + for (const auto& layer : dirs) { for (const auto& sd : layer->GetSubdirectories()) { - if (std::find(names.begin(), names.end(), sd->GetName()) == names.end()) - names.push_back(sd->GetName()); + out_names.emplace(sd->GetName()); } } - std::vector<VirtualDir> out; - out.reserve(names.size()); - for (const auto& subdir : names) + out.reserve(out_names.size()); + for (const auto& subdir : out_names) { out.emplace_back(GetSubdirectory(subdir)); + } return out; } 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) InputInterpreter::~InputInterpreter() = default; void InputInterpreter::PollInput() { + if (npad == nullptr) { + return; + } const auto button_state = npad->GetAndResetPressState(); 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 @@ #include "common/scope_exit.h" #include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_light_session.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" @@ -63,6 +64,7 @@ Result KClientPort::CreateSession(KClientSession** out) { R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); // Allocate a session normally. + // TODO: Dynamic resource limits session = KSession::Create(m_kernel); // Check that we successfully created a session. @@ -119,4 +121,71 @@ Result KClientPort::CreateSession(KClientSession** out) { R_SUCCEED(); } +Result KClientPort::CreateLightSession(KLightClientSession** out) { + // Declare the session we're going to allocate. + KLightSession* session{}; + + // Reserve a new session from the resource limit. + KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel), + Svc::LimitableResource::SessionCountMax); + R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); + + // Allocate a session normally. + // TODO: Dynamic resource limits + session = KLightSession::Create(m_kernel); + + // Check that we successfully created a session. + R_UNLESS(session != nullptr, ResultOutOfResource); + + // Update the session counts. + { + ON_RESULT_FAILURE { + session->Close(); + }; + + // Atomically increment the number of sessions. + s32 new_sessions; + { + const auto max = m_max_sessions; + auto cur_sessions = m_num_sessions.load(std::memory_order_acquire); + do { + R_UNLESS(cur_sessions < max, ResultOutOfSessions); + new_sessions = cur_sessions + 1; + } while (!m_num_sessions.compare_exchange_weak(cur_sessions, new_sessions, + std::memory_order_relaxed)); + } + + // Atomically update the peak session tracking. + { + auto peak = m_peak_sessions.load(std::memory_order_acquire); + do { + if (peak >= new_sessions) { + break; + } + } while (!m_peak_sessions.compare_exchange_weak(peak, new_sessions, + std::memory_order_relaxed)); + } + } + + // Initialize the session. + session->Initialize(this, m_parent->GetName()); + + // Commit the session reservation. + session_reservation.Commit(); + + // Register the session. + KLightSession::Register(m_kernel, session); + ON_RESULT_FAILURE { + session->GetClientSession().Close(); + session->GetServerSession().Close(); + }; + + // Enqueue the session with our parent. + R_TRY(m_parent->EnqueueSession(std::addressof(session->GetServerSession()))); + + // We succeeded, so set the output. + *out = std::addressof(session->GetClientSession()); + R_SUCCEED(); +} + } // 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 @@ namespace Kernel { +class KLightClientSession; class KClientSession; class KernelCore; class KPort; @@ -51,6 +52,7 @@ public: bool IsSignaled() const override; Result CreateSession(KClientSession** out); + Result CreateLightSession(KLightClientSession** out); private: 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 @@ namespace Kernel { -static constexpr u32 MessageBufferSize = 0x100; - -KClientSession::KClientSession(KernelCore& kernel) : KAutoObjectWithSlabHeapAndContainer{kernel} {} +KClientSession::KClientSession(KernelCore& kernel) : KAutoObject{kernel} {} KClientSession::~KClientSession() = default; void KClientSession::Destroy() { @@ -22,18 +20,30 @@ void KClientSession::Destroy() { void KClientSession::OnServerClosed() {} -Result KClientSession::SendSyncRequest() { +Result KClientSession::SendSyncRequest(uintptr_t address, size_t size) { + // Create a session request. + KSessionRequest* request = KSessionRequest::Create(m_kernel); + R_UNLESS(request != nullptr, ResultOutOfResource); + SCOPE_EXIT({ request->Close(); }); + + // Initialize the request. + request->Initialize(nullptr, address, size); + + // Send the request. + R_RETURN(m_parent->OnRequest(request)); +} + +Result KClientSession::SendAsyncRequest(KEvent* event, uintptr_t address, size_t size) { // Create a session request. KSessionRequest* request = KSessionRequest::Create(m_kernel); R_UNLESS(request != nullptr, ResultOutOfResource); SCOPE_EXIT({ request->Close(); }); // Initialize the request. - request->Initialize(nullptr, GetInteger(GetCurrentThread(m_kernel).GetTlsAddress()), - MessageBufferSize); + request->Initialize(event, address, size); // Send the request. - R_RETURN(m_parent->GetServerSession().OnRequest(request)); + R_RETURN(m_parent->OnRequest(request)); } } // 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 @@ #include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" -union Result; - -namespace Core::Memory { -class Memory; -} - -namespace Core::Timing { -class CoreTiming; -} - namespace Kernel { class KernelCore; class KSession; -class KThread; -class KClientSession final - : public KAutoObjectWithSlabHeapAndContainer<KClientSession, KAutoObjectWithList> { +class KClientSession final : public KAutoObject { KERNEL_AUTOOBJECT_TRAITS(KClientSession, KAutoObject); public: @@ -39,13 +27,13 @@ public: } void Destroy() override; - static void PostDestroy(uintptr_t arg) {} KSession* GetParent() const { return m_parent; } - Result SendSyncRequest(); + Result SendSyncRequest(uintptr_t address, size_t size); + Result SendAsyncRequest(KEvent* event, uintptr_t address, size_t size); void OnServerClosed(); 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_light_client_session.h" +#include "core/hle/kernel/k_light_session.h" +#include "core/hle/kernel/k_thread.h" + +namespace Kernel { + +KLightClientSession::KLightClientSession(KernelCore& kernel) : KAutoObject(kernel) {} + +KLightClientSession::~KLightClientSession() = default; + +void KLightClientSession::Destroy() { + m_parent->OnClientClosed(); +} + +void KLightClientSession::OnServerClosed() {} + +Result KLightClientSession::SendSyncRequest(u32* data) { + // Get the request thread. + KThread* cur_thread = GetCurrentThreadPointer(m_kernel); + + // Set the light data. + cur_thread->SetLightSessionData(data); + + // Send the request. + R_RETURN(m_parent->OnRequest(cur_thread)); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KLightSession; + +class KLightClientSession final : public KAutoObject { + KERNEL_AUTOOBJECT_TRAITS(KLightClientSession, KAutoObject); + +public: + explicit KLightClientSession(KernelCore& kernel); + ~KLightClientSession(); + + void Initialize(KLightSession* parent) { + // Set member variables. + m_parent = parent; + } + + virtual void Destroy() override; + + const KLightSession* GetParent() const { + return m_parent; + } + + Result SendSyncRequest(u32* data); + + void OnServerClosed(); + +private: + KLightSession* m_parent; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_light_server_session.h" +#include "core/hle/kernel/k_light_session.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +namespace { + +constexpr u64 InvalidThreadId = std::numeric_limits<u64>::max(); + +class ThreadQueueImplForKLightServerSessionRequest final : public KThreadQueue { +private: + KThread::WaiterList* m_wait_list; + +public: + ThreadQueueImplForKLightServerSessionRequest(KernelCore& kernel, KThread::WaiterList* wl) + : KThreadQueue(kernel), m_wait_list(wl) {} + + virtual void EndWait(KThread* waiting_thread, Result wait_result) override { + // Remove the thread from our wait list. + m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); + + // Invoke the base end wait handler. + KThreadQueue::EndWait(waiting_thread, wait_result); + } + + virtual void CancelWait(KThread* waiting_thread, Result wait_result, + bool cancel_timer_task) override { + // Remove the thread from our wait list. + m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + +class ThreadQueueImplForKLightServerSessionReceive final : public KThreadQueue { +private: + KThread** m_server_thread; + +public: + ThreadQueueImplForKLightServerSessionReceive(KernelCore& kernel, KThread** st) + : KThreadQueue(kernel), m_server_thread(st) {} + + virtual void EndWait(KThread* waiting_thread, Result wait_result) override { + // Clear the server thread. + *m_server_thread = nullptr; + + // Set the waiting thread as not cancelable. + waiting_thread->ClearCancellable(); + + // Invoke the base end wait handler. + KThreadQueue::EndWait(waiting_thread, wait_result); + } + + virtual void CancelWait(KThread* waiting_thread, Result wait_result, + bool cancel_timer_task) override { + // Clear the server thread. + *m_server_thread = nullptr; + + // Set the waiting thread as not cancelable. + waiting_thread->ClearCancellable(); + + // Invoke the base cancel wait handler. + KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); + } +}; + +} // namespace + +KLightServerSession::KLightServerSession(KernelCore& kernel) : KAutoObject(kernel) {} +KLightServerSession::~KLightServerSession() = default; + +void KLightServerSession::Destroy() { + this->CleanupRequests(); + + m_parent->OnServerClosed(); +} + +void KLightServerSession::OnClientClosed() { + this->CleanupRequests(); +} + +Result KLightServerSession::OnRequest(KThread* request_thread) { + ThreadQueueImplForKLightServerSessionRequest wait_queue(m_kernel, + std::addressof(m_request_list)); + + // Send the request. + { + // Lock the scheduler. + KScopedSchedulerLock sl(m_kernel); + + // Check that the server isn't closed. + R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed); + + // Check that the request thread isn't terminating. + R_UNLESS(!request_thread->IsTerminationRequested(), ResultTerminationRequested); + + // Add the request thread to our list. + m_request_list.push_back(*request_thread); + + // Begin waiting on the request. + request_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); + request_thread->BeginWait(std::addressof(wait_queue)); + + // If we have a server thread, end its wait. + if (m_server_thread != nullptr) { + m_server_thread->EndWait(ResultSuccess); + } + } + + // NOTE: Nintendo returns GetCurrentThread().GetWaitResult() here. + // This is technically incorrect, although it doesn't cause problems in practice + // because this is only ever called with request_thread = GetCurrentThreadPointer(). + R_RETURN(request_thread->GetWaitResult()); +} + +Result KLightServerSession::ReplyAndReceive(u32* data) { + // Set the server context. + GetCurrentThread(m_kernel).SetLightSessionData(data); + + // Reply, if we need to. + if (data[0] & KLightSession::ReplyFlag) { + KScopedSchedulerLock sl(m_kernel); + + // Check that we're open. + R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed); + R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed); + + // Check that we have a request to reply to. + R_UNLESS(m_current_request != nullptr, ResultInvalidState); + + // Check that the server thread id is correct. + R_UNLESS(m_server_thread_id == GetCurrentThread(m_kernel).GetId(), ResultInvalidState); + + // If we can reply, do so. + if (!m_current_request->IsTerminationRequested()) { + std::memcpy(m_current_request->GetLightSessionData(), + GetCurrentThread(m_kernel).GetLightSessionData(), KLightSession::DataSize); + m_current_request->EndWait(ResultSuccess); + } + + // Close our current request. + m_current_request->Close(); + + // Clear our current request. + m_current_request = nullptr; + m_server_thread_id = InvalidThreadId; + } + + // Create the wait queue for our receive. + ThreadQueueImplForKLightServerSessionReceive wait_queue(m_kernel, + std::addressof(m_server_thread)); + + // Receive. + while (true) { + // Try to receive a request. + { + KScopedSchedulerLock sl(m_kernel); + + // Check that we aren't already receiving. + R_UNLESS(m_server_thread == nullptr, ResultInvalidState); + R_UNLESS(m_server_thread_id == InvalidThreadId, ResultInvalidState); + + // Check that we're open. + R_UNLESS(!m_parent->IsClientClosed(), ResultSessionClosed); + R_UNLESS(!m_parent->IsServerClosed(), ResultSessionClosed); + + // Check that we're not terminating. + R_UNLESS(!GetCurrentThread(m_kernel).IsTerminationRequested(), + ResultTerminationRequested); + + // If we have a request available, use it. + if (auto head = m_request_list.begin(); head != m_request_list.end()) { + // Set our current request. + m_current_request = std::addressof(*head); + m_current_request->Open(); + + // Set our server thread id. + m_server_thread_id = GetCurrentThread(m_kernel).GetId(); + + // Copy the client request data. + std::memcpy(GetCurrentThread(m_kernel).GetLightSessionData(), + m_current_request->GetLightSessionData(), KLightSession::DataSize); + + // We successfully received. + R_SUCCEED(); + } + + // We need to wait for a request to come in. + + // Check if we were cancelled. + if (GetCurrentThread(m_kernel).IsWaitCancelled()) { + GetCurrentThread(m_kernel).ClearWaitCancelled(); + R_THROW(ResultCancelled); + } + + // Mark ourselves as cancellable. + GetCurrentThread(m_kernel).SetCancellable(); + + // Wait for a request to come in. + m_server_thread = GetCurrentThreadPointer(m_kernel); + GetCurrentThread(m_kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); + GetCurrentThread(m_kernel).BeginWait(std::addressof(wait_queue)); + } + + // We waited to receive a request; if our wait failed, return the failing result. + R_TRY(GetCurrentThread(m_kernel).GetWaitResult()); + } +} + +void KLightServerSession::CleanupRequests() { + // Cleanup all pending requests. + { + KScopedSchedulerLock sl(m_kernel); + + // Handle the current request. + if (m_current_request != nullptr) { + // Reply to the current request. + if (!m_current_request->IsTerminationRequested()) { + m_current_request->EndWait(ResultSessionClosed); + } + + // Clear our current request. + m_current_request->Close(); + m_current_request = nullptr; + m_server_thread_id = InvalidThreadId; + } + + // Reply to all other requests. + for (auto& thread : m_request_list) { + thread.EndWait(ResultSessionClosed); + } + + // Wait up our server thread, if we have one. + if (m_server_thread != nullptr) { + m_server_thread->EndWait(ResultSessionClosed); + } + } +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/kernel/k_auto_object.h" +#include "core/hle/kernel/k_thread.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KLightSession; + +class KLightServerSession final : public KAutoObject, + public Common::IntrusiveListBaseNode<KLightServerSession> { + KERNEL_AUTOOBJECT_TRAITS(KLightServerSession, KAutoObject); + +private: + KLightSession* m_parent{}; + KThread::WaiterList m_request_list{}; + KThread* m_current_request{}; + u64 m_server_thread_id{std::numeric_limits<u64>::max()}; + KThread* m_server_thread{}; + +public: + explicit KLightServerSession(KernelCore& kernel); + ~KLightServerSession(); + + void Initialize(KLightSession* parent) { + // Set member variables. */ + m_parent = parent; + } + + virtual void Destroy() override; + + constexpr const KLightSession* GetParent() const { + return m_parent; + } + + Result OnRequest(KThread* request_thread); + Result ReplyAndReceive(u32* data); + + void OnClientClosed(); + +private: + void CleanupRequests(); +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_client_port.h" +#include "core/hle/kernel/k_light_client_session.h" +#include "core/hle/kernel/k_light_server_session.h" +#include "core/hle/kernel/k_light_session.h" +#include "core/hle/kernel/k_process.h" + +namespace Kernel { + +KLightSession::KLightSession(KernelCore& kernel) + : KAutoObjectWithSlabHeapAndContainer(kernel), m_server(kernel), m_client(kernel) {} +KLightSession::~KLightSession() = default; + +void KLightSession::Initialize(KClientPort* client_port, uintptr_t name) { + // Increment reference count. + // Because reference count is one on creation, this will result + // in a reference count of two. Thus, when both server and client are closed + // this object will be destroyed. + this->Open(); + + // Create our sub sessions. + KAutoObject::Create(std::addressof(m_server)); + KAutoObject::Create(std::addressof(m_client)); + + // Initialize our sub sessions. + m_server.Initialize(this); + m_client.Initialize(this); + + // Set state and name. + m_state = State::Normal; + m_name = name; + + // Set our owner process. + m_process = GetCurrentProcessPointer(m_kernel); + m_process->Open(); + + // Set our port. + m_port = client_port; + if (m_port != nullptr) { + m_port->Open(); + } + + // Mark initialized. + m_initialized = true; +} + +void KLightSession::Finalize() { + if (m_port != nullptr) { + m_port->OnSessionFinalized(); + m_port->Close(); + } +} + +void KLightSession::OnServerClosed() { + if (m_state == State::Normal) { + m_state = State::ServerClosed; + m_client.OnServerClosed(); + } + + this->Close(); +} + +void KLightSession::OnClientClosed() { + if (m_state == State::Normal) { + m_state = State::ClientClosed; + m_server.OnClientClosed(); + } + + this->Close(); +} + +void KLightSession::PostDestroy(uintptr_t arg) { + // Release the session count resource the owner process holds. + KProcess* owner = reinterpret_cast<KProcess*>(arg); + owner->ReleaseResource(Svc::LimitableResource::SessionCountMax, 1); + owner->Close(); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/kernel/k_light_client_session.h" +#include "core/hle/kernel/k_light_server_session.h" +#include "core/hle/kernel/slab_helpers.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KClientPort; +class KProcess; + +// TODO: SupportDynamicExpansion for SlabHeap +class KLightSession final + : public KAutoObjectWithSlabHeapAndContainer<KLightSession, KAutoObjectWithList> { + KERNEL_AUTOOBJECT_TRAITS(KLightSession, KAutoObject); + +private: + enum class State : u8 { + Invalid = 0, + Normal = 1, + ClientClosed = 2, + ServerClosed = 3, + }; + +public: + static constexpr size_t DataSize = sizeof(u32) * 7; + static constexpr u32 ReplyFlag = (1U << 31); + +private: + KLightServerSession m_server; + KLightClientSession m_client; + State m_state{State::Invalid}; + KClientPort* m_port{}; + uintptr_t m_name{}; + KProcess* m_process{}; + bool m_initialized{}; + +public: + explicit KLightSession(KernelCore& kernel); + ~KLightSession(); + + void Initialize(KClientPort* client_port, uintptr_t name); + void Finalize() override; + + bool IsInitialized() const override { + return m_initialized; + } + uintptr_t GetPostDestroyArgument() const override { + return reinterpret_cast<uintptr_t>(m_process); + } + + static void PostDestroy(uintptr_t arg); + + void OnServerClosed(); + void OnClientClosed(); + + bool IsServerClosed() const { + return m_state != State::Normal; + } + bool IsClientClosed() const { + return m_state != State::Normal; + } + + Result OnRequest(KThread* request_thread) { + R_RETURN(m_server.OnRequest(request_thread)); + } + + KLightClientSession& GetClientSession() { + return m_client; + } + KLightServerSession& GetServerSession() { + return m_server; + } + const KLightClientSession& GetClientSession() const { + return m_client; + } + const KLightServerSession& GetServerSession() const { + return m_server; + } +}; + +} // 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 } else { // Set all the allocated memory. for (const auto& block : *out) { - std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern, - block.GetSize()); + m_system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(block.GetAddress()) - + Core::DramMemoryMap::Base, + block.GetSize(), fill_pattern); } } 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: }; template <typename AddressType> -void InvalidateInstructionCache(Core::System& system, AddressType addr, u64 size) { - system.InvalidateCpuInstructionCacheRange(GetInteger(addr), size); +void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 size) { + // TODO: lock the process list + for (auto& process : kernel.GetProcessList()) { + for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + auto* interface = process->GetArmInterface(i); + if (interface) { + interface->InvalidateCacheRange(GetInteger(addr), size); + } + } + } +} + +void ClearBackingRegion(Core::System& system, KPhysicalAddress addr, u64 size, u32 fill_value) { + system.DeviceMemory().buffer.ClearBackingRegion(GetInteger(addr) - Core::DramMemoryMap::Base, + size, fill_value); } template <typename AddressType> @@ -1261,7 +1274,7 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr bool reprotected_pages = false; SCOPE_EXIT({ if (reprotected_pages && any_code_pages) { - InvalidateInstructionCache(m_system, dst_address, size); + InvalidateInstructionCache(m_kernel, dst_address, size); } }); @@ -1355,8 +1368,7 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) { // Clear all the newly allocated pages. for (const auto& it : pg) { - std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), - static_cast<u32>(m_heap_fill_value), it.GetSize()); + ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value); } // Lock the table. @@ -1562,8 +1574,7 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce // Clear all pages. for (const auto& it : pg) { - std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), - static_cast<u32>(m_heap_fill_value), it.GetSize()); + ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value); } // Map the pages. @@ -1997,7 +2008,7 @@ Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t s for (const auto& block : pg) { StoreDataCache(GetHeapVirtualPointer(m_kernel, block.GetAddress()), block.GetSize()); } - InvalidateInstructionCache(m_system, addr, size); + InvalidateInstructionCache(m_kernel, addr, size); } R_SUCCEED(); @@ -2151,8 +2162,7 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) { // Clear all the newly allocated pages. for (const auto& it : pg) { - std::memset(GetHeapVirtualPointer(m_kernel, it.GetAddress()), m_heap_fill_value, - it.GetSize()); + ClearBackingRegion(m_system, it.GetAddress(), it.GetSize(), m_heap_fill_value); } // Map the pages. @@ -3239,7 +3249,7 @@ Result KPageTableBase::WriteDebugMemory(KProcessAddress dst_address, KProcessAdd R_TRY(PerformCopy()); // Invalidate the instruction cache, as this svc allows modifying executable pages. - InvalidateInstructionCache(m_system, dst_address, size); + InvalidateInstructionCache(m_kernel, dst_address, size); R_SUCCEED(); } 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) { R_SUCCEED(); } +Result KPort::EnqueueSession(KLightServerSession* session) { + KScopedSchedulerLock sl{m_kernel}; + + R_UNLESS(m_state == State::Normal, ResultPortClosed); + + m_server.EnqueueSession(session); + R_SUCCEED(); +} + } // 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 @@ namespace Kernel { +class KLightServerSession; class KServerSession; class KPort final : public KAutoObjectWithSlabHeapAndContainer<KPort, KAutoObjectWithList> { @@ -38,6 +39,7 @@ public: bool IsServerClosed() const; Result EnqueueSession(KServerSession* session); + Result EnqueueSession(KLightServerSession* session); KClientPort& GetClientPort() { 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 @@ #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/k_worker_task_manager.h" +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#ifdef HAS_NCE +#include "core/arm/nce/arm_nce.h" +#endif + namespace Kernel { namespace { @@ -957,10 +963,8 @@ Result KProcess::Run(s32 priority, size_t stack_size) { R_TRY(m_handle_table.Add(std::addressof(thread_handle), main_thread)); // Set the thread arguments. - main_thread->GetContext32().cpu_registers[0] = 0; - main_thread->GetContext64().cpu_registers[0] = 0; - main_thread->GetContext32().cpu_registers[1] = thread_handle; - main_thread->GetContext64().cpu_registers[1] = thread_handle; + main_thread->GetContext().r[0] = 0; + main_thread->GetContext().r[1] = thread_handle; // Update our state. this->ChangeState((state == State::Created) ? State::Running : State::RunningAttached); @@ -1199,6 +1203,9 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: m_is_hbl = is_hbl; m_ideal_core_id = metadata.GetMainThreadCore(); + // Set up emulation context. + this->InitializeInterfaces(); + // We succeeded. R_SUCCEED(); } @@ -1227,6 +1234,31 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) { #endif } +void KProcess::InitializeInterfaces() { + this->GetMemory().SetCurrentPageTable(*this); + +#ifdef HAS_NCE + if (this->Is64Bit() && Settings::IsNceEnabled()) { + for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i); + } + } else +#endif + if (this->Is64Bit()) { + for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>( + m_kernel.System(), m_kernel.IsMulticore(), this, + static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i); + } + } else { + for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { + m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>( + m_kernel.System(), m_kernel.IsMulticore(), this, + static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i); + } + } +} + bool KProcess::InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type) { const auto watch{std::find_if(m_watchpoints.begin(), m_watchpoints.end(), [&](const auto& wp) { 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 @@ #include <map> +#include "core/arm/arm_interface.h" #include "core/file_sys/program_metadata.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_address_arbiter.h" @@ -106,6 +107,8 @@ private: bool m_is_suspended{}; bool m_is_immortal{}; bool m_is_handle_table_initialized{}; + std::array<std::unique_ptr<Core::ArmInterface>, Core::Hardware::NUM_CPU_CORES> + m_arm_interfaces{}; std::array<KThread*, Core::Hardware::NUM_CPU_CORES> m_running_threads{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_idle_counts{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> m_running_thread_switch_counts{}; @@ -476,6 +479,10 @@ public: } #endif + Core::ArmInterface* GetArmInterface(size_t core_index) const { + return m_arm_interfaces[core_index].get(); + } + public: // Attempts to insert a watchpoint into a free slot. Returns false if none are available. bool InsertWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointType type); @@ -493,6 +500,8 @@ public: void LoadModule(CodeSet code_set, KProcessAddress base_addr); + void InitializeInterfaces(); + Core::Memory::Memory& GetMemory() const; public: 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 @@ #include "core/hle/kernel/k_scoped_lock.h" #include "core/hle/kernel/svc_types.h" -namespace Core { -class ARM_Interface; -} - namespace Kernel { class 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() { } void KScheduler::Unload(KThread* thread) { - auto& cpu_core = m_kernel.System().ArmInterface(m_core_id); - cpu_core.SaveContext(thread->GetContext32()); - cpu_core.SaveContext(thread->GetContext64()); - // Save the TPIDR_EL0 system register in case it was modified. - thread->SetTpidrEl0(cpu_core.GetTPIDR_EL0()); - cpu_core.ClearExclusiveState(); + m_kernel.PhysicalCore(m_core_id).SaveContext(thread); // Check if the thread is terminated by checking the DPC flags. if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) { @@ -509,14 +504,7 @@ void KScheduler::Unload(KThread* thread) { } void KScheduler::Reload(KThread* thread) { - auto& cpu_core = m_kernel.System().ArmInterface(m_core_id); - auto* process = thread->GetOwnerProcess(); - cpu_core.LoadContext(thread->GetContext32()); - cpu_core.LoadContext(thread->GetContext64()); - cpu_core.SetTlsAddress(GetInteger(thread->GetTlsAddress())); - cpu_core.SetTPIDR_EL0(thread->GetTpidrEl0()); - cpu_core.LoadWatchpointArray(process ? &process->GetWatchpoints() : nullptr); - cpu_core.ClearExclusiveState(); + m_kernel.PhysicalCore(m_core_id).LoadContext(thread); } void 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 { void KServerPort::CleanupSessions() { // Ensure our preconditions are met. if (this->IsLight()) { - UNIMPLEMENTED(); + ASSERT(m_session_list.empty()); + } else { + ASSERT(m_light_session_list.empty()); } // Cleanup the session list. while (true) { - // Get the last session in the list + // Get the last session in the list. KServerSession* session = nullptr; { KScopedSchedulerLock sl{m_kernel}; @@ -49,6 +51,26 @@ void KServerPort::CleanupSessions() { break; } } + + // Cleanup the light session list. + while (true) { + // Get the last session in the list. + KLightServerSession* session = nullptr; + { + KScopedSchedulerLock sl{m_kernel}; + if (!m_light_session_list.empty()) { + session = std::addressof(m_light_session_list.front()); + m_light_session_list.pop_front(); + } + } + + // Close the session. + if (session != nullptr) { + session->Close(); + } else { + break; + } + } } void KServerPort::Destroy() { @@ -64,8 +86,7 @@ void KServerPort::Destroy() { bool KServerPort::IsSignaled() const { if (this->IsLight()) { - UNIMPLEMENTED(); - return false; + return !m_light_session_list.empty(); } else { return !m_session_list.empty(); } @@ -83,6 +104,18 @@ void KServerPort::EnqueueSession(KServerSession* session) { } } +void KServerPort::EnqueueSession(KLightServerSession* session) { + ASSERT(this->IsLight()); + + KScopedSchedulerLock sl{m_kernel}; + + // Add the session to our queue. + m_light_session_list.push_back(*session); + if (m_light_session_list.size() == 1) { + this->NotifyAvailable(); + } +} + KServerSession* KServerPort::AcceptSession() { ASSERT(!this->IsLight()); @@ -98,4 +131,19 @@ KServerSession* KServerPort::AcceptSession() { return session; } +KLightServerSession* KServerPort::AcceptLightSession() { + ASSERT(this->IsLight()); + + KScopedSchedulerLock sl{m_kernel}; + + // Return the first session in the list. + if (m_light_session_list.empty()) { + return nullptr; + } + + KLightServerSession* session = std::addressof(m_light_session_list.front()); + m_light_session_list.pop_front(); + return session; +} + } // 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 @@ #include "common/intrusive_list.h" +#include "core/hle/kernel/k_light_server_session.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_synchronization_object.h" @@ -28,8 +29,10 @@ public: void Initialize(KPort* parent); void EnqueueSession(KServerSession* session); + void EnqueueSession(KLightServerSession* session); KServerSession* AcceptSession(); + KLightServerSession* AcceptLightSession(); const KPort* GetParent() const { return m_parent; @@ -43,10 +46,12 @@ public: private: using SessionList = Common::IntrusiveListBaseTraits<KServerSession>::ListType; + using LightSessionList = Common::IntrusiveListBaseTraits<KLightServerSession>::ListType; void CleanupSessions(); SessionList m_session_list{}; + LightSessionList m_light_session_list{}; KPort* m_parent{}; }; 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 size_t client_buffer_size = request->GetSize(); // bool recv_list_broken = false; + if (!client_message) { + client_message = GetInteger(client_thread->GetTlsAddress()); + client_buffer_size = MessageBufferSize; + } + // Receive the message. Core::Memory::Memory& memory{client_thread->GetOwnerProcess()->GetMemory()}; if (out_context != nullptr) { @@ -462,8 +467,7 @@ Result KServerSession::ReceiveRequest(std::shared_ptr<Service::HLERequestContext std::make_shared<Service::HLERequestContext>(m_kernel, memory, this, client_thread); (*out_context)->SetSessionRequestManager(manager); (*out_context) - ->PopulateFromIncomingCommandBuffer(client_thread->GetOwnerProcess()->GetHandleTable(), - cmd_buf); + ->PopulateFromIncomingCommandBuffer(*client_thread->GetOwnerProcess(), cmd_buf); } else { KThread* server_thread = GetCurrentThreadPointer(m_kernel); 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: return this->GetState() != State::Normal; } + Result OnRequest(KSessionRequest* request) { + R_RETURN(m_server.OnRequest(request)); + } + KClientSession& GetClientSession() { return m_client; } 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 { constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1; -static void ResetThreadContext32(Kernel::KThread::ThreadContext32& context, u32 stack_top, - u32 entry_point, u32 arg) { - context = {}; - context.cpu_registers[0] = arg; - context.cpu_registers[15] = entry_point; - context.cpu_registers[13] = stack_top; - context.fpscr = 0; -} - -static void ResetThreadContext64(Kernel::KThread::ThreadContext64& context, u64 stack_top, - u64 entry_point, u64 arg) { - context = {}; - context.cpu_registers[0] = arg; - context.cpu_registers[18] = Kernel::KSystemControl::GenerateRandomU64() | 1; - context.pc = entry_point; - context.sp = stack_top; - context.fpcr = 0; - context.fpsr = 0; +static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point, + u64 arg) { + ctx = {}; + ctx.r[0] = arg; + ctx.r[15] = entry_point; + ctx.r[13] = stack_top; + ctx.fpcr = 0; + ctx.fpsr = 0; +} + +static void ResetThreadContext64(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point, + u64 arg) { + ctx = {}; + ctx.r[0] = arg; + ctx.r[18] = Kernel::KSystemControl::GenerateRandomU64() | 1; + ctx.pc = entry_point; + ctx.sp = stack_top; + ctx.fpcr = 0; + ctx.fpsr = 0; } } // namespace @@ -223,9 +224,11 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, KProcessAddress } // Initialize thread context. - ResetThreadContext64(m_thread_context_64, GetInteger(user_stack_top), GetInteger(func), arg); - ResetThreadContext32(m_thread_context_32, static_cast<u32>(GetInteger(user_stack_top)), - static_cast<u32>(GetInteger(func)), static_cast<u32>(arg)); + if (m_parent != nullptr && !m_parent->Is64Bit()) { + ResetThreadContext32(m_thread_context, GetInteger(user_stack_top), GetInteger(func), arg); + } else { + ResetThreadContext64(m_thread_context, GetInteger(user_stack_top), GetInteger(func), arg); + } // Setup the stack parameters. StackParameters& sp = this->GetStackParameters(); @@ -823,20 +826,7 @@ void KThread::CloneFpuStatus() { ASSERT(this->GetOwnerProcess() != nullptr); ASSERT(this->GetOwnerProcess() == GetCurrentProcessPointer(m_kernel)); - if (this->GetOwnerProcess()->Is64Bit()) { - // Clone FPSR and FPCR. - ThreadContext64 cur_ctx{}; - m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx); - - this->GetContext64().fpcr = cur_ctx.fpcr; - this->GetContext64().fpsr = cur_ctx.fpsr; - } else { - // Clone FPSCR. - ThreadContext32 cur_ctx{}; - m_kernel.System().CurrentArmInterface().SaveContext(cur_ctx); - - this->GetContext32().fpscr = cur_ctx.fpscr; - } + m_kernel.CurrentPhysicalCore().CloneFpuStatus(this); } Result KThread::SetActivity(Svc::ThreadActivity activity) { @@ -912,7 +902,7 @@ Result KThread::SetActivity(Svc::ThreadActivity activity) { R_SUCCEED(); } -Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) { +Result KThread::GetThreadContext3(Svc::ThreadContext* out) { // Lock ourselves. KScopedLightLock lk{m_activity_pause_lock}; @@ -926,18 +916,16 @@ Result KThread::GetThreadContext3(Common::ScratchBuffer<u8>& out) { // If we're not terminating, get the thread's user context. if (!this->IsTerminationRequested()) { + *out = m_thread_context; + + // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. + constexpr u32 El0Aarch64PsrMask = 0xF0000000; + constexpr u32 El0Aarch32PsrMask = 0xFE0FFE20; + if (m_parent->Is64Bit()) { - // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. - auto context = GetContext64(); - context.pstate &= 0xFF0FFE20; - out.resize_destructive(sizeof(context)); - std::memcpy(out.data(), std::addressof(context), sizeof(context)); + out->pstate &= El0Aarch64PsrMask; } else { - // Mask away mode bits, interrupt bits, IL bit, and other reserved bits. - auto context = GetContext32(); - context.cpsr &= 0xFF0FFE20; - out.resize_destructive(sizeof(context)); - std::memcpy(out.data(), std::addressof(context), sizeof(context)); + out->pstate &= El0Aarch32PsrMask; } } } 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 { namespace Memory { class Memory; } -class ARM_Interface; class System; } // namespace Core @@ -137,8 +136,6 @@ public: ~KThread() override; public: - using ThreadContext32 = Core::ARM_Interface::ThreadContext32; - using ThreadContext64 = Core::ARM_Interface::ThreadContext64; using WaiterList = Common::IntrusiveListBaseTraits<KThread>::ListType; /** @@ -246,31 +243,22 @@ public: * @returns The value of the TPIDR_EL0 register. */ u64 GetTpidrEl0() const { - return m_thread_context_64.tpidr; + return m_thread_context.tpidr; } /// Sets the value of the TPIDR_EL0 Read/Write system register for this thread. void SetTpidrEl0(u64 value) { - m_thread_context_64.tpidr = value; - m_thread_context_32.tpidr = static_cast<u32>(value); + m_thread_context.tpidr = value; } void CloneFpuStatus(); - ThreadContext32& GetContext32() { - return m_thread_context_32; + Svc::ThreadContext& GetContext() { + return m_thread_context; } - const ThreadContext32& GetContext32() const { - return m_thread_context_32; - } - - ThreadContext64& GetContext64() { - return m_thread_context_64; - } - - const ThreadContext64& GetContext64() const { - return m_thread_context_64; + const Svc::ThreadContext& GetContext() const { + return m_thread_context; } std::shared_ptr<Common::Fiber>& GetHostContext(); @@ -397,6 +385,13 @@ public: m_cancellable = false; } + u32* GetLightSessionData() const { + return m_light_ipc_data; + } + void SetLightSessionData(u32* data) { + m_light_ipc_data = data; + } + bool IsTerminationRequested() const { return m_termination_requested || GetRawState() == ThreadState::Terminated; } @@ -577,7 +572,7 @@ public: void RemoveWaiter(KThread* thread); - Result GetThreadContext3(Common::ScratchBuffer<u8>& out); + Result GetThreadContext3(Svc::ThreadContext* out); KThread* RemoveUserWaiterByKey(bool* out_has_waiters, KProcessAddress key) { return this->RemoveWaiterByKey(out_has_waiters, key, false); @@ -734,8 +729,7 @@ private: std::function<void()>&& init_func); // For core KThread implementation - ThreadContext32 m_thread_context_32{}; - ThreadContext64 m_thread_context_64{}; + Svc::ThreadContext m_thread_context{}; Common::IntrusiveListNode m_process_list_node; Common::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{}; 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 { RegisterHostThread(nullptr); } - void InitializeCores() { - for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - cores[core_id]->Initialize((*application_process).Is64Bit()); - system.ApplicationMemory().SetCurrentPageTable(*application_process, core_id); - } - } - void TerminateApplicationProcess() { application_process.load()->Terminate(); } @@ -142,7 +135,6 @@ struct KernelCore::Impl { obj = nullptr; } }; - CleanupObject(hid_shared_mem); CleanupObject(font_shared_mem); CleanupObject(irs_shared_mem); CleanupObject(time_shared_mem); @@ -205,7 +197,7 @@ struct KernelCore::Impl { const s32 core{static_cast<s32>(i)}; schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel()); - cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]); + cores[i] = std::make_unique<Kernel::PhysicalCore>(system.Kernel(), i); auto* main_thread{Kernel::KThread::Create(system.Kernel())}; main_thread->SetCurrentCore(core); @@ -751,22 +743,16 @@ struct KernelCore::Impl { void InitializeHackSharedMemory(KernelCore& kernel) { // Setup memory regions for emulated processes // TODO(bunnei): These should not be hardcoded regions initialized within the kernel - constexpr std::size_t hid_size{0x40000}; constexpr std::size_t font_size{0x1100000}; constexpr std::size_t irs_size{0x8000}; constexpr std::size_t time_size{0x1000}; constexpr std::size_t hidbus_size{0x1000}; - hid_shared_mem = KSharedMemory::Create(system.Kernel()); font_shared_mem = KSharedMemory::Create(system.Kernel()); irs_shared_mem = KSharedMemory::Create(system.Kernel()); time_shared_mem = KSharedMemory::Create(system.Kernel()); hidbus_shared_mem = KSharedMemory::Create(system.Kernel()); - hid_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, - Svc::MemoryPermission::Read, hid_size); - KSharedMemory::Register(kernel, hid_shared_mem); - font_shared_mem->Initialize(system.DeviceMemory(), nullptr, Svc::MemoryPermission::None, Svc::MemoryPermission::Read, font_size); KSharedMemory::Register(kernel, font_shared_mem); @@ -880,10 +866,6 @@ void KernelCore::Initialize() { impl->Initialize(*this); } -void KernelCore::InitializeCores() { - impl->InitializeCores(); -} - void KernelCore::Shutdown() { impl->Shutdown(); } @@ -993,21 +975,6 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const { return *impl->global_object_list_container; } -void KernelCore::InvalidateAllInstructionCaches() { - for (auto& physical_core : impl->cores) { - physical_core->ArmInterface().ClearInstructionCache(); - } -} - -void KernelCore::InvalidateCpuInstructionCacheRange(KProcessAddress addr, std::size_t size) { - for (auto& physical_core : impl->cores) { - if (!physical_core->IsInitialized()) { - continue; - } - physical_core->ArmInterface().InvalidateCacheRange(GetInteger(addr), size); - } -} - void KernelCore::PrepareReschedule(std::size_t id) { // TODO: Reimplement, this } @@ -1216,14 +1183,6 @@ const KSystemResource& KernelCore::GetSystemSystemResource() const { return *impl->sys_system_resource; } -Kernel::KSharedMemory& KernelCore::GetHidSharedMem() { - return *impl->hid_shared_mem; -} - -const Kernel::KSharedMemory& KernelCore::GetHidSharedMem() const { - return *impl->hid_shared_mem; -} - Kernel::KSharedMemory& KernelCore::GetFontSharedMem() { return *impl->font_shared_mem; } @@ -1366,6 +1325,7 @@ struct KernelCore::SlabHeapContainer { KSlabHeap<KProcess> process; KSlabHeap<KResourceLimit> resource_limit; KSlabHeap<KSession> session; + KSlabHeap<KLightSession> light_session; KSlabHeap<KSharedMemory> shared_memory; KSlabHeap<KSharedMemoryInfo> shared_memory_info; KSlabHeap<KThread> thread; @@ -1396,6 +1356,8 @@ KSlabHeap<T>& KernelCore::SlabHeap() { return slab_heap_container->resource_limit; } else if constexpr (std::is_same_v<T, KSession>) { return slab_heap_container->session; + } else if constexpr (std::is_same_v<T, KLightSession>) { + return slab_heap_container->light_session; } else if constexpr (std::is_same_v<T, KSharedMemory>) { return slab_heap_container->shared_memory; } else if constexpr (std::is_same_v<T, KSharedMemoryInfo>) { @@ -1433,6 +1395,7 @@ template KSlabHeap<KPort>& KernelCore::SlabHeap(); template KSlabHeap<KProcess>& KernelCore::SlabHeap(); template KSlabHeap<KResourceLimit>& KernelCore::SlabHeap(); template KSlabHeap<KSession>& KernelCore::SlabHeap(); +template KSlabHeap<KLightSession>& KernelCore::SlabHeap(); template KSlabHeap<KSharedMemory>& KernelCore::SlabHeap(); template KSlabHeap<KSharedMemoryInfo>& KernelCore::SlabHeap(); template 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: /// Resets the kernel to a clean slate for use. void Initialize(); - /// Initializes the CPU cores. - void InitializeCores(); - /// Clears all resources in use by the kernel instance. void Shutdown(); @@ -181,10 +178,6 @@ public: const KAutoObjectWithListContainer& ObjectListContainer() const; - void InvalidateAllInstructionCaches(); - - void InvalidateCpuInstructionCacheRange(KProcessAddress addr, std::size_t size); - /// Registers all kernel objects with the global emulation state, this is purely for tracking /// leaks after emulation has been shutdown. void RegisterKernelObject(KAutoObject* object); @@ -246,12 +239,6 @@ public: /// Gets the system resource manager. const KSystemResource& GetSystemSystemResource() const; - /// Gets the shared memory object for HID services. - Kernel::KSharedMemory& GetHidSharedMem(); - - /// Gets the shared memory object for HID services. - const Kernel::KSharedMemory& GetHidSharedMem() const; - /// Gets the shared memory object for font services. Kernel::KSharedMemory& GetFontSharedMem(); 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 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/scope_exit.h" #include "common/settings.h" -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" -#ifdef HAS_NCE -#include "core/arm/nce/arm_nce.h" -#endif #include "core/core.h" -#include "core/hle/kernel/k_scheduler.h" +#include "core/debugger/debugger.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" +#include "core/hle/kernel/svc.h" namespace Kernel { -PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KScheduler& scheduler) - : m_core_index{core_index}, m_system{system}, m_scheduler{scheduler} { -#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) - // TODO(bunnei): Initialization relies on a core being available. We may later replace this with - // an NCE interface or a 32-bit instance of Dynarmic. This should be abstracted out to a CPU - // manager. - auto& kernel = system.Kernel(); - m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( - system, kernel.IsMulticore(), - reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()), - m_core_index); -#else -#error Platform not supported yet. -#endif +PhysicalCore::PhysicalCore(KernelCore& kernel, std::size_t core_index) + : m_kernel{kernel}, m_core_index{core_index} { + m_is_single_core = !kernel.IsMulticore(); } - PhysicalCore::~PhysicalCore() = default; -void PhysicalCore::Initialize(bool is_64_bit) { -#if defined(HAS_NCE) - if (Settings::IsNceEnabled()) { - m_arm_interface = std::make_unique<Core::ARM_NCE>(m_system, m_system.Kernel().IsMulticore(), - m_core_index); +void PhysicalCore::RunThread(Kernel::KThread* thread) { + auto* process = thread->GetOwnerProcess(); + auto& system = m_kernel.System(); + auto* interface = process->GetArmInterface(m_core_index); + + interface->Initialize(); + + const auto EnterContext = [&]() { + system.EnterCPUProfile(); + + // Lock the core context. + std::scoped_lock lk{m_guard}; + + // Check if we are already interrupted. If we are, we can just stop immediately. + if (m_is_interrupted) { + return false; + } + + // Mark that we are running. + m_arm_interface = interface; + m_current_thread = thread; + + // Acquire the lock on the thread parameters. + // This allows us to force synchronization with Interrupt. + interface->LockThread(thread); + + return true; + }; + + const auto ExitContext = [&]() { + // Unlock the thread. + interface->UnlockThread(thread); + + // Lock the core context. + std::scoped_lock lk{m_guard}; + + // On exit, we no longer are running. + m_arm_interface = nullptr; + m_current_thread = nullptr; + + system.ExitCPUProfile(); + }; + + while (true) { + // If the thread is scheduled for termination, exit. + if (thread->HasDpc() && thread->IsTerminationRequested()) { + thread->Exit(); + } + + // Notify the debugger and go to sleep if a step was performed + // and this thread has been scheduled again. + if (thread->GetStepState() == StepState::StepPerformed) { + system.GetDebugger().NotifyThreadStopped(thread); + thread->RequestSuspend(SuspendType::Debug); + return; + } + + // Otherwise, run the thread. + Core::HaltReason hr{}; + { + // If we were interrupted, exit immediately. + if (!EnterContext()) { + return; + } + + if (thread->GetStepState() == StepState::StepPending) { + hr = interface->StepThread(thread); + + if (True(hr & Core::HaltReason::StepThread)) { + thread->SetStepState(StepState::StepPerformed); + } + } else { + hr = interface->RunThread(thread); + } + + ExitContext(); + } + + // Determine why we stopped. + const bool supervisor_call = True(hr & Core::HaltReason::SupervisorCall); + const bool prefetch_abort = True(hr & Core::HaltReason::PrefetchAbort); + const bool breakpoint = True(hr & Core::HaltReason::InstructionBreakpoint); + const bool data_abort = True(hr & Core::HaltReason::DataAbort); + const bool interrupt = True(hr & Core::HaltReason::BreakLoop); + + // Since scheduling may occur here, we cannot use any cached + // state after returning from calls we make. + + // Notify the debugger and go to sleep if a breakpoint was hit, + // or if the thread is unable to continue for any reason. + if (breakpoint || prefetch_abort) { + if (breakpoint) { + interface->RewindBreakpointInstruction(); + } + if (system.DebuggerEnabled()) { + system.GetDebugger().NotifyThreadStopped(thread); + } else { + interface->LogBacktrace(process); + } + thread->RequestSuspend(SuspendType::Debug); + return; + } + + // Notify the debugger and go to sleep on data abort. + if (data_abort) { + if (system.DebuggerEnabled()) { + system.GetDebugger().NotifyThreadWatchpoint(thread, *interface->HaltedWatchpoint()); + } + thread->RequestSuspend(SuspendType::Debug); + return; + } + + // Handle system calls. + if (supervisor_call) { + // Perform call. + Svc::Call(system, interface->GetSvcNumber()); + return; + } + + // Handle external interrupt sources. + if (interrupt || m_is_single_core) { + return; + } + } +} + +void PhysicalCore::LoadContext(const KThread* thread) { + auto* const process = thread->GetOwnerProcess(); + if (!process) { + // Kernel threads do not run on emulated CPU cores. return; } -#endif -#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64) - auto& kernel = m_system.Kernel(); - if (!is_64_bit) { - // We already initialized a 64-bit core, replace with a 32-bit one. - m_arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( - m_system, kernel.IsMulticore(), - reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()), - m_core_index); + + auto* interface = process->GetArmInterface(m_core_index); + if (interface) { + interface->SetContext(thread->GetContext()); + interface->SetTpidrroEl0(GetInteger(thread->GetTlsAddress())); + interface->SetWatchpointArray(&process->GetWatchpoints()); } -#else -#error Platform not supported yet. -#endif } -void PhysicalCore::Run() { - m_arm_interface->Run(); - m_arm_interface->ClearExclusiveState(); +void PhysicalCore::LoadSvcArguments(const KProcess& process, std::span<const uint64_t, 8> args) { + process.GetArmInterface(m_core_index)->SetSvcArguments(args); +} + +void PhysicalCore::SaveContext(KThread* thread) const { + auto* const process = thread->GetOwnerProcess(); + if (!process) { + // Kernel threads do not run on emulated CPU cores. + return; + } + + auto* interface = process->GetArmInterface(m_core_index); + if (interface) { + interface->GetContext(thread->GetContext()); + } +} + +void PhysicalCore::SaveSvcArguments(KProcess& process, std::span<uint64_t, 8> args) const { + process.GetArmInterface(m_core_index)->GetSvcArguments(args); +} + +void PhysicalCore::CloneFpuStatus(KThread* dst) const { + auto* process = dst->GetOwnerProcess(); + + Svc::ThreadContext ctx{}; + process->GetArmInterface(m_core_index)->GetContext(ctx); + + dst->GetContext().fpcr = ctx.fpcr; + dst->GetContext().fpsr = ctx.fpsr; +} + +void PhysicalCore::LogBacktrace() { + auto* process = GetCurrentProcessPointer(m_kernel); + if (!process) { + return; + } + + auto* interface = process->GetArmInterface(m_core_index); + if (interface) { + interface->LogBacktrace(process); + } } void PhysicalCore::Idle() { @@ -69,16 +213,31 @@ bool PhysicalCore::IsInterrupted() const { } void PhysicalCore::Interrupt() { - std::unique_lock lk{m_guard}; + // Lock core context. + std::scoped_lock lk{m_guard}; + + // Load members. + auto* arm_interface = m_arm_interface; + auto* thread = m_current_thread; + + // Add interrupt flag. m_is_interrupted = true; - m_arm_interface->SignalInterrupt(); - m_on_interrupt.notify_all(); + + // Interrupt ourselves. + m_on_interrupt.notify_one(); + + // If there is no thread running, we are done. + if (arm_interface == nullptr) { + return; + } + + // Interrupt the CPU. + arm_interface->SignalInterrupt(thread); } void PhysicalCore::ClearInterrupt() { - std::unique_lock lk{m_guard}; + std::scoped_lock lk{m_guard}; m_is_interrupted = false; - m_arm_interface->ClearInterrupt(); } } // 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 @@ #include "core/arm/arm_interface.h" namespace Kernel { -class KScheduler; +class KernelCore; } // namespace Kernel namespace Core { @@ -23,62 +23,55 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_); + PhysicalCore(KernelCore& kernel, std::size_t core_index); ~PhysicalCore(); YUZU_NON_COPYABLE(PhysicalCore); YUZU_NON_MOVEABLE(PhysicalCore); - /// Initialize the core for the specified parameters. - void Initialize(bool is_64_bit); + // Execute guest code running on the given thread. + void RunThread(KThread* thread); - /// Execute current jit state - void Run(); + // Copy context from thread to current core. + void LoadContext(const KThread* thread); + void LoadSvcArguments(const KProcess& process, std::span<const uint64_t, 8> args); + // Copy context from current core to thread. + void SaveContext(KThread* thread) const; + void SaveSvcArguments(KProcess& process, std::span<uint64_t, 8> args) const; + + // Copy floating point status registers to the target thread. + void CloneFpuStatus(KThread* dst) const; + + // Log backtrace of current processor state. + void LogBacktrace(); + + // Wait for an interrupt. void Idle(); - /// Interrupt this physical core. + // Interrupt this core. void Interrupt(); - /// Clear this core's interrupt + // Clear this core's interrupt. void ClearInterrupt(); - /// Check if this core is interrupted + // Check if this core is interrupted. bool IsInterrupted() const; - bool IsInitialized() const { - return m_arm_interface != nullptr; - } - - Core::ARM_Interface& ArmInterface() { - return *m_arm_interface; - } - - const Core::ARM_Interface& ArmInterface() const { - return *m_arm_interface; - } - std::size_t CoreIndex() const { return m_core_index; } - Kernel::KScheduler& Scheduler() { - return m_scheduler; - } - - const Kernel::KScheduler& Scheduler() const { - return m_scheduler; - } - private: + KernelCore& m_kernel; const std::size_t m_core_index; - Core::System& m_system; - Kernel::KScheduler& m_scheduler; std::mutex m_guard; std::condition_variable m_on_interrupt; - std::unique_ptr<Core::ARM_Interface> m_arm_interface; + Core::ArmInterface* m_arm_interface{}; + KThread* m_current_thread{}; bool m_is_interrupted{}; + bool m_is_single_core{}; }; } // 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 @@ namespace Kernel::Svc { -static uint32_t GetReg32(Core::System& system, int n) { - return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n)); +static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) { + return static_cast<uint32_t>(args[n]); } -static void SetReg32(Core::System& system, int n, uint32_t result) { - system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result)); +static void SetArg32(std::span<uint64_t, 8> args, int n, uint32_t result) { + args[n] = result; } -static uint64_t GetReg64(Core::System& system, int n) { - return system.CurrentArmInterface().GetReg(n); +static uint64_t GetArg64(std::span<uint64_t, 8> args, int n) { + return args[n]; } -static void SetReg64(Core::System& system, int n, uint64_t result) { - system.CurrentArmInterface().SetReg(n, result); +static void SetArg64(std::span<uint64_t, 8> args, int n, uint64_t result) { + args[n] = result; } // Like bit_cast, but handles the case when the source and dest @@ -79,37 +79,37 @@ static_assert(sizeof(int64_t) == 8); static_assert(sizeof(uint32_t) == 4); static_assert(sizeof(uint64_t) == 8); -static void SvcWrap_SetHeapSize64From32(Core::System& system) { +static void SvcWrap_SetHeapSize64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_address{}; uint32_t size{}; - size = Convert<uint32_t>(GetReg32(system, 1)); + size = Convert<uint32_t>(GetArg32(args, 1)); ret = SetHeapSize64From32(system, std::addressof(out_address), size); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_address)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_address)); } -static void SvcWrap_SetMemoryPermission64From32(Core::System& system) { +static void SvcWrap_SetMemoryPermission64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; uint32_t size{}; MemoryPermission perm{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); - perm = Convert<MemoryPermission>(GetReg32(system, 2)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); + perm = Convert<MemoryPermission>(GetArg32(args, 2)); ret = SetMemoryPermission64From32(system, address, size, perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SetMemoryAttribute64From32(Core::System& system) { +static void SvcWrap_SetMemoryAttribute64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; @@ -117,69 +117,69 @@ static void SvcWrap_SetMemoryAttribute64From32(Core::System& system) { uint32_t mask{}; uint32_t attr{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); - mask = Convert<uint32_t>(GetReg32(system, 2)); - attr = Convert<uint32_t>(GetReg32(system, 3)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); + mask = Convert<uint32_t>(GetArg32(args, 2)); + attr = Convert<uint32_t>(GetArg32(args, 3)); ret = SetMemoryAttribute64From32(system, address, size, mask, attr); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_MapMemory64From32(Core::System& system) { +static void SvcWrap_MapMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t dst_address{}; uint32_t src_address{}; uint32_t size{}; - dst_address = Convert<uint32_t>(GetReg32(system, 0)); - src_address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); + dst_address = Convert<uint32_t>(GetArg32(args, 0)); + src_address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); ret = MapMemory64From32(system, dst_address, src_address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapMemory64From32(Core::System& system) { +static void SvcWrap_UnmapMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t dst_address{}; uint32_t src_address{}; uint32_t size{}; - dst_address = Convert<uint32_t>(GetReg32(system, 0)); - src_address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); + dst_address = Convert<uint32_t>(GetArg32(args, 0)); + src_address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); ret = UnmapMemory64From32(system, dst_address, src_address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_QueryMemory64From32(Core::System& system) { +static void SvcWrap_QueryMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; PageInfo out_page_info{}; uint32_t out_memory_info{}; uint32_t address{}; - out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); - address = Convert<uint32_t>(GetReg32(system, 2)); + out_memory_info = Convert<uint32_t>(GetArg32(args, 0)); + address = Convert<uint32_t>(GetArg32(args, 2)); ret = QueryMemory64From32(system, out_memory_info, std::addressof(out_page_info), address); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_page_info)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_page_info)); } -static void SvcWrap_ExitProcess64From32(Core::System& system) { +static void SvcWrap_ExitProcess64From32(Core::System& system, std::span<uint64_t, 8> args) { ExitProcess64From32(system); } -static void SvcWrap_CreateThread64From32(Core::System& system) { +static void SvcWrap_CreateThread64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -189,143 +189,143 @@ static void SvcWrap_CreateThread64From32(Core::System& system) { int32_t priority{}; int32_t core_id{}; - func = Convert<uint32_t>(GetReg32(system, 1)); - arg = Convert<uint32_t>(GetReg32(system, 2)); - stack_bottom = Convert<uint32_t>(GetReg32(system, 3)); - priority = Convert<int32_t>(GetReg32(system, 0)); - core_id = Convert<int32_t>(GetReg32(system, 4)); + func = Convert<uint32_t>(GetArg32(args, 1)); + arg = Convert<uint32_t>(GetArg32(args, 2)); + stack_bottom = Convert<uint32_t>(GetArg32(args, 3)); + priority = Convert<int32_t>(GetArg32(args, 0)); + core_id = Convert<int32_t>(GetArg32(args, 4)); ret = CreateThread64From32(system, std::addressof(out_handle), func, arg, stack_bottom, priority, core_id); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_StartThread64From32(Core::System& system) { +static void SvcWrap_StartThread64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; - thread_handle = Convert<Handle>(GetReg32(system, 0)); + thread_handle = Convert<Handle>(GetArg32(args, 0)); ret = StartThread64From32(system, thread_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_ExitThread64From32(Core::System& system) { +static void SvcWrap_ExitThread64From32(Core::System& system, std::span<uint64_t, 8> args) { ExitThread64From32(system); } -static void SvcWrap_SleepThread64From32(Core::System& system) { +static void SvcWrap_SleepThread64From32(Core::System& system, std::span<uint64_t, 8> args) { int64_t ns{}; std::array<uint32_t, 2> ns_gather{}; - ns_gather[0] = GetReg32(system, 0); - ns_gather[1] = GetReg32(system, 1); + ns_gather[0] = GetArg32(args, 0); + ns_gather[1] = GetArg32(args, 1); ns = Convert<int64_t>(ns_gather); SleepThread64From32(system, ns); } -static void SvcWrap_GetThreadPriority64From32(Core::System& system) { +static void SvcWrap_GetThreadPriority64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_priority{}; Handle thread_handle{}; - thread_handle = Convert<Handle>(GetReg32(system, 1)); + thread_handle = Convert<Handle>(GetArg32(args, 1)); ret = GetThreadPriority64From32(system, std::addressof(out_priority), thread_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_priority)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_priority)); } -static void SvcWrap_SetThreadPriority64From32(Core::System& system) { +static void SvcWrap_SetThreadPriority64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; int32_t priority{}; - thread_handle = Convert<Handle>(GetReg32(system, 0)); - priority = Convert<int32_t>(GetReg32(system, 1)); + thread_handle = Convert<Handle>(GetArg32(args, 0)); + priority = Convert<int32_t>(GetArg32(args, 1)); ret = SetThreadPriority64From32(system, thread_handle, priority); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_GetThreadCoreMask64From32(Core::System& system) { +static void SvcWrap_GetThreadCoreMask64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_core_id{}; uint64_t out_affinity_mask{}; Handle thread_handle{}; - thread_handle = Convert<Handle>(GetReg32(system, 2)); + thread_handle = Convert<Handle>(GetArg32(args, 2)); ret = GetThreadCoreMask64From32(system, std::addressof(out_core_id), std::addressof(out_affinity_mask), thread_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_core_id)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_core_id)); auto out_affinity_mask_scatter = Convert<std::array<uint32_t, 2>>(out_affinity_mask); - SetReg32(system, 2, out_affinity_mask_scatter[0]); - SetReg32(system, 3, out_affinity_mask_scatter[1]); + SetArg32(args, 2, out_affinity_mask_scatter[0]); + SetArg32(args, 3, out_affinity_mask_scatter[1]); } -static void SvcWrap_SetThreadCoreMask64From32(Core::System& system) { +static void SvcWrap_SetThreadCoreMask64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; int32_t core_id{}; uint64_t affinity_mask{}; - thread_handle = Convert<Handle>(GetReg32(system, 0)); - core_id = Convert<int32_t>(GetReg32(system, 1)); + thread_handle = Convert<Handle>(GetArg32(args, 0)); + core_id = Convert<int32_t>(GetArg32(args, 1)); std::array<uint32_t, 2> affinity_mask_gather{}; - affinity_mask_gather[0] = GetReg32(system, 2); - affinity_mask_gather[1] = GetReg32(system, 3); + affinity_mask_gather[0] = GetArg32(args, 2); + affinity_mask_gather[1] = GetArg32(args, 3); affinity_mask = Convert<uint64_t>(affinity_mask_gather); ret = SetThreadCoreMask64From32(system, thread_handle, core_id, affinity_mask); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_GetCurrentProcessorNumber64From32(Core::System& system) { +static void SvcWrap_GetCurrentProcessorNumber64From32(Core::System& system, std::span<uint64_t, 8> args) { int32_t ret{}; ret = GetCurrentProcessorNumber64From32(system); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SignalEvent64From32(Core::System& system) { +static void SvcWrap_SignalEvent64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle event_handle{}; - event_handle = Convert<Handle>(GetReg32(system, 0)); + event_handle = Convert<Handle>(GetArg32(args, 0)); ret = SignalEvent64From32(system, event_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_ClearEvent64From32(Core::System& system) { +static void SvcWrap_ClearEvent64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle event_handle{}; - event_handle = Convert<Handle>(GetReg32(system, 0)); + event_handle = Convert<Handle>(GetArg32(args, 0)); ret = ClearEvent64From32(system, event_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_MapSharedMemory64From32(Core::System& system) { +static void SvcWrap_MapSharedMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle shmem_handle{}; @@ -333,33 +333,33 @@ static void SvcWrap_MapSharedMemory64From32(Core::System& system) { uint32_t size{}; MemoryPermission map_perm{}; - shmem_handle = Convert<Handle>(GetReg32(system, 0)); - address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); - map_perm = Convert<MemoryPermission>(GetReg32(system, 3)); + shmem_handle = Convert<Handle>(GetArg32(args, 0)); + address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); + map_perm = Convert<MemoryPermission>(GetArg32(args, 3)); ret = MapSharedMemory64From32(system, shmem_handle, address, size, map_perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapSharedMemory64From32(Core::System& system) { +static void SvcWrap_UnmapSharedMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle shmem_handle{}; uint32_t address{}; uint32_t size{}; - shmem_handle = Convert<Handle>(GetReg32(system, 0)); - address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); + shmem_handle = Convert<Handle>(GetArg32(args, 0)); + address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); ret = UnmapSharedMemory64From32(system, shmem_handle, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_CreateTransferMemory64From32(Core::System& system) { +static void SvcWrap_CreateTransferMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -367,41 +367,41 @@ static void SvcWrap_CreateTransferMemory64From32(Core::System& system) { uint32_t size{}; MemoryPermission map_perm{}; - address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); - map_perm = Convert<MemoryPermission>(GetReg32(system, 3)); + address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); + map_perm = Convert<MemoryPermission>(GetArg32(args, 3)); ret = CreateTransferMemory64From32(system, std::addressof(out_handle), address, size, map_perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_CloseHandle64From32(Core::System& system) { +static void SvcWrap_CloseHandle64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle handle{}; - handle = Convert<Handle>(GetReg32(system, 0)); + handle = Convert<Handle>(GetArg32(args, 0)); ret = CloseHandle64From32(system, handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_ResetSignal64From32(Core::System& system) { +static void SvcWrap_ResetSignal64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle handle{}; - handle = Convert<Handle>(GetReg32(system, 0)); + handle = Convert<Handle>(GetArg32(args, 0)); ret = ResetSignal64From32(system, handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_WaitSynchronization64From32(Core::System& system) { +static void SvcWrap_WaitSynchronization64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_index{}; @@ -409,60 +409,60 @@ static void SvcWrap_WaitSynchronization64From32(Core::System& system) { int32_t num_handles{}; int64_t timeout_ns{}; - handles = Convert<uint32_t>(GetReg32(system, 1)); - num_handles = Convert<int32_t>(GetReg32(system, 2)); + handles = Convert<uint32_t>(GetArg32(args, 1)); + num_handles = Convert<int32_t>(GetArg32(args, 2)); std::array<uint32_t, 2> timeout_ns_gather{}; - timeout_ns_gather[0] = GetReg32(system, 0); - timeout_ns_gather[1] = GetReg32(system, 3); + timeout_ns_gather[0] = GetArg32(args, 0); + timeout_ns_gather[1] = GetArg32(args, 3); timeout_ns = Convert<int64_t>(timeout_ns_gather); ret = WaitSynchronization64From32(system, std::addressof(out_index), handles, num_handles, timeout_ns); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_index)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_index)); } -static void SvcWrap_CancelSynchronization64From32(Core::System& system) { +static void SvcWrap_CancelSynchronization64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle handle{}; - handle = Convert<Handle>(GetReg32(system, 0)); + handle = Convert<Handle>(GetArg32(args, 0)); ret = CancelSynchronization64From32(system, handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_ArbitrateLock64From32(Core::System& system) { +static void SvcWrap_ArbitrateLock64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; uint32_t address{}; uint32_t tag{}; - thread_handle = Convert<Handle>(GetReg32(system, 0)); - address = Convert<uint32_t>(GetReg32(system, 1)); - tag = Convert<uint32_t>(GetReg32(system, 2)); + thread_handle = Convert<Handle>(GetArg32(args, 0)); + address = Convert<uint32_t>(GetArg32(args, 1)); + tag = Convert<uint32_t>(GetArg32(args, 2)); ret = ArbitrateLock64From32(system, thread_handle, address, tag); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_ArbitrateUnlock64From32(Core::System& system) { +static void SvcWrap_ArbitrateUnlock64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; - address = Convert<uint32_t>(GetReg32(system, 0)); + address = Convert<uint32_t>(GetArg32(args, 0)); ret = ArbitrateUnlock64From32(system, address); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_WaitProcessWideKeyAtomic64From32(Core::System& system) { +static void SvcWrap_WaitProcessWideKeyAtomic64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; @@ -470,82 +470,82 @@ static void SvcWrap_WaitProcessWideKeyAtomic64From32(Core::System& system) { uint32_t tag{}; int64_t timeout_ns{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - cv_key = Convert<uint32_t>(GetReg32(system, 1)); - tag = Convert<uint32_t>(GetReg32(system, 2)); + address = Convert<uint32_t>(GetArg32(args, 0)); + cv_key = Convert<uint32_t>(GetArg32(args, 1)); + tag = Convert<uint32_t>(GetArg32(args, 2)); std::array<uint32_t, 2> timeout_ns_gather{}; - timeout_ns_gather[0] = GetReg32(system, 3); - timeout_ns_gather[1] = GetReg32(system, 4); + timeout_ns_gather[0] = GetArg32(args, 3); + timeout_ns_gather[1] = GetArg32(args, 4); timeout_ns = Convert<int64_t>(timeout_ns_gather); ret = WaitProcessWideKeyAtomic64From32(system, address, cv_key, tag, timeout_ns); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SignalProcessWideKey64From32(Core::System& system) { +static void SvcWrap_SignalProcessWideKey64From32(Core::System& system, std::span<uint64_t, 8> args) { uint32_t cv_key{}; int32_t count{}; - cv_key = Convert<uint32_t>(GetReg32(system, 0)); - count = Convert<int32_t>(GetReg32(system, 1)); + cv_key = Convert<uint32_t>(GetArg32(args, 0)); + count = Convert<int32_t>(GetArg32(args, 1)); SignalProcessWideKey64From32(system, cv_key, count); } -static void SvcWrap_GetSystemTick64From32(Core::System& system) { +static void SvcWrap_GetSystemTick64From32(Core::System& system, std::span<uint64_t, 8> args) { int64_t ret{}; ret = GetSystemTick64From32(system); auto ret_scatter = Convert<std::array<uint32_t, 2>>(ret); - SetReg32(system, 0, ret_scatter[0]); - SetReg32(system, 1, ret_scatter[1]); + SetArg32(args, 0, ret_scatter[0]); + SetArg32(args, 1, ret_scatter[1]); } -static void SvcWrap_ConnectToNamedPort64From32(Core::System& system) { +static void SvcWrap_ConnectToNamedPort64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; uint32_t name{}; - name = Convert<uint32_t>(GetReg32(system, 1)); + name = Convert<uint32_t>(GetArg32(args, 1)); ret = ConnectToNamedPort64From32(system, std::addressof(out_handle), name); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_SendSyncRequest64From32(Core::System& system) { +static void SvcWrap_SendSyncRequest64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle session_handle{}; - session_handle = Convert<Handle>(GetReg32(system, 0)); + session_handle = Convert<Handle>(GetArg32(args, 0)); ret = SendSyncRequest64From32(system, session_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SendSyncRequestWithUserBuffer64From32(Core::System& system) { +static void SvcWrap_SendSyncRequestWithUserBuffer64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t message_buffer{}; uint32_t message_buffer_size{}; Handle session_handle{}; - message_buffer = Convert<uint32_t>(GetReg32(system, 0)); - message_buffer_size = Convert<uint32_t>(GetReg32(system, 1)); - session_handle = Convert<Handle>(GetReg32(system, 2)); + message_buffer = Convert<uint32_t>(GetArg32(args, 0)); + message_buffer_size = Convert<uint32_t>(GetArg32(args, 1)); + session_handle = Convert<Handle>(GetArg32(args, 2)); ret = SendSyncRequestWithUserBuffer64From32(system, message_buffer, message_buffer_size, session_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SendAsyncRequestWithUserBuffer64From32(Core::System& system) { +static void SvcWrap_SendAsyncRequestWithUserBuffer64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_event_handle{}; @@ -553,83 +553,83 @@ static void SvcWrap_SendAsyncRequestWithUserBuffer64From32(Core::System& system) uint32_t message_buffer_size{}; Handle session_handle{}; - message_buffer = Convert<uint32_t>(GetReg32(system, 1)); - message_buffer_size = Convert<uint32_t>(GetReg32(system, 2)); - session_handle = Convert<Handle>(GetReg32(system, 3)); + message_buffer = Convert<uint32_t>(GetArg32(args, 1)); + message_buffer_size = Convert<uint32_t>(GetArg32(args, 2)); + session_handle = Convert<Handle>(GetArg32(args, 3)); ret = SendAsyncRequestWithUserBuffer64From32(system, std::addressof(out_event_handle), message_buffer, message_buffer_size, session_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_event_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_event_handle)); } -static void SvcWrap_GetProcessId64From32(Core::System& system) { +static void SvcWrap_GetProcessId64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_process_id{}; Handle process_handle{}; - process_handle = Convert<Handle>(GetReg32(system, 1)); + process_handle = Convert<Handle>(GetArg32(args, 1)); ret = GetProcessId64From32(system, std::addressof(out_process_id), process_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_process_id_scatter = Convert<std::array<uint32_t, 2>>(out_process_id); - SetReg32(system, 1, out_process_id_scatter[0]); - SetReg32(system, 2, out_process_id_scatter[1]); + SetArg32(args, 1, out_process_id_scatter[0]); + SetArg32(args, 2, out_process_id_scatter[1]); } -static void SvcWrap_GetThreadId64From32(Core::System& system) { +static void SvcWrap_GetThreadId64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_thread_id{}; Handle thread_handle{}; - thread_handle = Convert<Handle>(GetReg32(system, 1)); + thread_handle = Convert<Handle>(GetArg32(args, 1)); ret = GetThreadId64From32(system, std::addressof(out_thread_id), thread_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id); - SetReg32(system, 1, out_thread_id_scatter[0]); - SetReg32(system, 2, out_thread_id_scatter[1]); + SetArg32(args, 1, out_thread_id_scatter[0]); + SetArg32(args, 2, out_thread_id_scatter[1]); } -static void SvcWrap_Break64From32(Core::System& system) { +static void SvcWrap_Break64From32(Core::System& system, std::span<uint64_t, 8> args) { BreakReason break_reason{}; uint32_t arg{}; uint32_t size{}; - break_reason = Convert<BreakReason>(GetReg32(system, 0)); - arg = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); + break_reason = Convert<BreakReason>(GetArg32(args, 0)); + arg = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); Break64From32(system, break_reason, arg, size); } -static void SvcWrap_OutputDebugString64From32(Core::System& system) { +static void SvcWrap_OutputDebugString64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t debug_str{}; uint32_t len{}; - debug_str = Convert<uint32_t>(GetReg32(system, 0)); - len = Convert<uint32_t>(GetReg32(system, 1)); + debug_str = Convert<uint32_t>(GetArg32(args, 0)); + len = Convert<uint32_t>(GetArg32(args, 1)); ret = OutputDebugString64From32(system, debug_str, len); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_ReturnFromException64From32(Core::System& system) { +static void SvcWrap_ReturnFromException64From32(Core::System& system, std::span<uint64_t, 8> args) { Result result{}; - result = Convert<Result>(GetReg32(system, 0)); + result = Convert<Result>(GetArg32(args, 0)); ReturnFromException64From32(system, result); } -static void SvcWrap_GetInfo64From32(Core::System& system) { +static void SvcWrap_GetInfo64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out{}; @@ -637,68 +637,68 @@ static void SvcWrap_GetInfo64From32(Core::System& system) { Handle handle{}; uint64_t info_subtype{}; - info_type = Convert<InfoType>(GetReg32(system, 1)); - handle = Convert<Handle>(GetReg32(system, 2)); + info_type = Convert<InfoType>(GetArg32(args, 1)); + handle = Convert<Handle>(GetArg32(args, 2)); std::array<uint32_t, 2> info_subtype_gather{}; - info_subtype_gather[0] = GetReg32(system, 0); - info_subtype_gather[1] = GetReg32(system, 3); + info_subtype_gather[0] = GetArg32(args, 0); + info_subtype_gather[1] = GetArg32(args, 3); info_subtype = Convert<uint64_t>(info_subtype_gather); ret = GetInfo64From32(system, std::addressof(out), info_type, handle, info_subtype); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_scatter = Convert<std::array<uint32_t, 2>>(out); - SetReg32(system, 1, out_scatter[0]); - SetReg32(system, 2, out_scatter[1]); + SetArg32(args, 1, out_scatter[0]); + SetArg32(args, 2, out_scatter[1]); } -static void SvcWrap_FlushEntireDataCache64From32(Core::System& system) { +static void SvcWrap_FlushEntireDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) { FlushEntireDataCache64From32(system); } -static void SvcWrap_FlushDataCache64From32(Core::System& system) { +static void SvcWrap_FlushDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; uint32_t size{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); ret = FlushDataCache64From32(system, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_MapPhysicalMemory64From32(Core::System& system) { +static void SvcWrap_MapPhysicalMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; uint32_t size{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); ret = MapPhysicalMemory64From32(system, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapPhysicalMemory64From32(Core::System& system) { +static void SvcWrap_UnmapPhysicalMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; uint32_t size{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); ret = UnmapPhysicalMemory64From32(system, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_GetDebugFutureThreadInfo64From32(Core::System& system) { +static void SvcWrap_GetDebugFutureThreadInfo64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; ilp32::LastThreadContext out_context{}; @@ -706,26 +706,26 @@ static void SvcWrap_GetDebugFutureThreadInfo64From32(Core::System& system) { Handle debug_handle{}; int64_t ns{}; - debug_handle = Convert<Handle>(GetReg32(system, 2)); + debug_handle = Convert<Handle>(GetArg32(args, 2)); std::array<uint32_t, 2> ns_gather{}; - ns_gather[0] = GetReg32(system, 0); - ns_gather[1] = GetReg32(system, 1); + ns_gather[0] = GetArg32(args, 0); + ns_gather[1] = GetArg32(args, 1); ns = Convert<int64_t>(ns_gather); ret = GetDebugFutureThreadInfo64From32(system, std::addressof(out_context), std::addressof(out_thread_id), debug_handle, ns); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context); - SetReg32(system, 1, out_context_scatter[0]); - SetReg32(system, 2, out_context_scatter[1]); - SetReg32(system, 3, out_context_scatter[2]); - SetReg32(system, 4, out_context_scatter[3]); + SetArg32(args, 1, out_context_scatter[0]); + SetArg32(args, 2, out_context_scatter[1]); + SetArg32(args, 3, out_context_scatter[2]); + SetArg32(args, 4, out_context_scatter[3]); auto out_thread_id_scatter = Convert<std::array<uint32_t, 2>>(out_thread_id); - SetReg32(system, 5, out_thread_id_scatter[0]); - SetReg32(system, 6, out_thread_id_scatter[1]); + SetArg32(args, 5, out_thread_id_scatter[0]); + SetArg32(args, 6, out_thread_id_scatter[1]); } -static void SvcWrap_GetLastThreadInfo64From32(Core::System& system) { +static void SvcWrap_GetLastThreadInfo64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; ilp32::LastThreadContext out_context{}; @@ -734,81 +734,81 @@ static void SvcWrap_GetLastThreadInfo64From32(Core::System& system) { ret = GetLastThreadInfo64From32(system, std::addressof(out_context), std::addressof(out_tls_address), std::addressof(out_flags)); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_context_scatter = Convert<std::array<uint32_t, 4>>(out_context); - SetReg32(system, 1, out_context_scatter[0]); - SetReg32(system, 2, out_context_scatter[1]); - SetReg32(system, 3, out_context_scatter[2]); - SetReg32(system, 4, out_context_scatter[3]); - SetReg32(system, 5, Convert<uint32_t>(out_tls_address)); - SetReg32(system, 6, Convert<uint32_t>(out_flags)); + SetArg32(args, 1, out_context_scatter[0]); + SetArg32(args, 2, out_context_scatter[1]); + SetArg32(args, 3, out_context_scatter[2]); + SetArg32(args, 4, out_context_scatter[3]); + SetArg32(args, 5, Convert<uint32_t>(out_tls_address)); + SetArg32(args, 6, Convert<uint32_t>(out_flags)); } -static void SvcWrap_GetResourceLimitLimitValue64From32(Core::System& system) { +static void SvcWrap_GetResourceLimitLimitValue64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int64_t out_limit_value{}; Handle resource_limit_handle{}; LimitableResource which{}; - resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); - which = Convert<LimitableResource>(GetReg32(system, 2)); + resource_limit_handle = Convert<Handle>(GetArg32(args, 1)); + which = Convert<LimitableResource>(GetArg32(args, 2)); ret = GetResourceLimitLimitValue64From32(system, std::addressof(out_limit_value), resource_limit_handle, which); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_limit_value_scatter = Convert<std::array<uint32_t, 2>>(out_limit_value); - SetReg32(system, 1, out_limit_value_scatter[0]); - SetReg32(system, 2, out_limit_value_scatter[1]); + SetArg32(args, 1, out_limit_value_scatter[0]); + SetArg32(args, 2, out_limit_value_scatter[1]); } -static void SvcWrap_GetResourceLimitCurrentValue64From32(Core::System& system) { +static void SvcWrap_GetResourceLimitCurrentValue64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int64_t out_current_value{}; Handle resource_limit_handle{}; LimitableResource which{}; - resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); - which = Convert<LimitableResource>(GetReg32(system, 2)); + resource_limit_handle = Convert<Handle>(GetArg32(args, 1)); + which = Convert<LimitableResource>(GetArg32(args, 2)); ret = GetResourceLimitCurrentValue64From32(system, std::addressof(out_current_value), resource_limit_handle, which); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_current_value_scatter = Convert<std::array<uint32_t, 2>>(out_current_value); - SetReg32(system, 1, out_current_value_scatter[0]); - SetReg32(system, 2, out_current_value_scatter[1]); + SetArg32(args, 1, out_current_value_scatter[0]); + SetArg32(args, 2, out_current_value_scatter[1]); } -static void SvcWrap_SetThreadActivity64From32(Core::System& system) { +static void SvcWrap_SetThreadActivity64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; ThreadActivity thread_activity{}; - thread_handle = Convert<Handle>(GetReg32(system, 0)); - thread_activity = Convert<ThreadActivity>(GetReg32(system, 1)); + thread_handle = Convert<Handle>(GetArg32(args, 0)); + thread_activity = Convert<ThreadActivity>(GetArg32(args, 1)); ret = SetThreadActivity64From32(system, thread_handle, thread_activity); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_GetThreadContext364From32(Core::System& system) { +static void SvcWrap_GetThreadContext364From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t out_context{}; Handle thread_handle{}; - out_context = Convert<uint32_t>(GetReg32(system, 0)); - thread_handle = Convert<Handle>(GetReg32(system, 1)); + out_context = Convert<uint32_t>(GetArg32(args, 0)); + thread_handle = Convert<Handle>(GetArg32(args, 1)); ret = GetThreadContext364From32(system, out_context, thread_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_WaitForAddress64From32(Core::System& system) { +static void SvcWrap_WaitForAddress64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; @@ -816,20 +816,20 @@ static void SvcWrap_WaitForAddress64From32(Core::System& system) { int32_t value{}; int64_t timeout_ns{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - arb_type = Convert<ArbitrationType>(GetReg32(system, 1)); - value = Convert<int32_t>(GetReg32(system, 2)); + address = Convert<uint32_t>(GetArg32(args, 0)); + arb_type = Convert<ArbitrationType>(GetArg32(args, 1)); + value = Convert<int32_t>(GetArg32(args, 2)); std::array<uint32_t, 2> timeout_ns_gather{}; - timeout_ns_gather[0] = GetReg32(system, 3); - timeout_ns_gather[1] = GetReg32(system, 4); + timeout_ns_gather[0] = GetArg32(args, 3); + timeout_ns_gather[1] = GetArg32(args, 4); timeout_ns = Convert<int64_t>(timeout_ns_gather); ret = WaitForAddress64From32(system, address, arb_type, value, timeout_ns); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SignalToAddress64From32(Core::System& system) { +static void SvcWrap_SignalToAddress64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; @@ -837,53 +837,53 @@ static void SvcWrap_SignalToAddress64From32(Core::System& system) { int32_t value{}; int32_t count{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - signal_type = Convert<SignalType>(GetReg32(system, 1)); - value = Convert<int32_t>(GetReg32(system, 2)); - count = Convert<int32_t>(GetReg32(system, 3)); + address = Convert<uint32_t>(GetArg32(args, 0)); + signal_type = Convert<SignalType>(GetArg32(args, 1)); + value = Convert<int32_t>(GetArg32(args, 2)); + count = Convert<int32_t>(GetArg32(args, 3)); ret = SignalToAddress64From32(system, address, signal_type, value, count); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SynchronizePreemptionState64From32(Core::System& system) { +static void SvcWrap_SynchronizePreemptionState64From32(Core::System& system, std::span<uint64_t, 8> args) { SynchronizePreemptionState64From32(system); } -static void SvcWrap_GetResourceLimitPeakValue64From32(Core::System& system) { +static void SvcWrap_GetResourceLimitPeakValue64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int64_t out_peak_value{}; Handle resource_limit_handle{}; LimitableResource which{}; - resource_limit_handle = Convert<Handle>(GetReg32(system, 1)); - which = Convert<LimitableResource>(GetReg32(system, 2)); + resource_limit_handle = Convert<Handle>(GetArg32(args, 1)); + which = Convert<LimitableResource>(GetArg32(args, 2)); ret = GetResourceLimitPeakValue64From32(system, std::addressof(out_peak_value), resource_limit_handle, which); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_peak_value_scatter = Convert<std::array<uint32_t, 2>>(out_peak_value); - SetReg32(system, 1, out_peak_value_scatter[0]); - SetReg32(system, 2, out_peak_value_scatter[1]); + SetArg32(args, 1, out_peak_value_scatter[0]); + SetArg32(args, 2, out_peak_value_scatter[1]); } -static void SvcWrap_CreateIoPool64From32(Core::System& system) { +static void SvcWrap_CreateIoPool64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; IoPoolType which{}; - which = Convert<IoPoolType>(GetReg32(system, 1)); + which = Convert<IoPoolType>(GetArg32(args, 1)); ret = CreateIoPool64From32(system, std::addressof(out_handle), which); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_CreateIoRegion64From32(Core::System& system) { +static void SvcWrap_CreateIoRegion64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -893,53 +893,53 @@ static void SvcWrap_CreateIoRegion64From32(Core::System& system) { MemoryMapping mapping{}; MemoryPermission perm{}; - io_pool = Convert<Handle>(GetReg32(system, 1)); + io_pool = Convert<Handle>(GetArg32(args, 1)); std::array<uint32_t, 2> physical_address_gather{}; - physical_address_gather[0] = GetReg32(system, 2); - physical_address_gather[1] = GetReg32(system, 3); + physical_address_gather[0] = GetArg32(args, 2); + physical_address_gather[1] = GetArg32(args, 3); physical_address = Convert<uint64_t>(physical_address_gather); - size = Convert<uint32_t>(GetReg32(system, 0)); - mapping = Convert<MemoryMapping>(GetReg32(system, 4)); - perm = Convert<MemoryPermission>(GetReg32(system, 5)); + size = Convert<uint32_t>(GetArg32(args, 0)); + mapping = Convert<MemoryMapping>(GetArg32(args, 4)); + perm = Convert<MemoryPermission>(GetArg32(args, 5)); ret = CreateIoRegion64From32(system, std::addressof(out_handle), io_pool, physical_address, size, mapping, perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_KernelDebug64From32(Core::System& system) { +static void SvcWrap_KernelDebug64From32(Core::System& system, std::span<uint64_t, 8> args) { KernelDebugType kern_debug_type{}; uint64_t arg0{}; uint64_t arg1{}; uint64_t arg2{}; - kern_debug_type = Convert<KernelDebugType>(GetReg32(system, 0)); + kern_debug_type = Convert<KernelDebugType>(GetArg32(args, 0)); std::array<uint32_t, 2> arg0_gather{}; - arg0_gather[0] = GetReg32(system, 2); - arg0_gather[1] = GetReg32(system, 3); + arg0_gather[0] = GetArg32(args, 2); + arg0_gather[1] = GetArg32(args, 3); arg0 = Convert<uint64_t>(arg0_gather); std::array<uint32_t, 2> arg1_gather{}; - arg1_gather[0] = GetReg32(system, 1); - arg1_gather[1] = GetReg32(system, 4); + arg1_gather[0] = GetArg32(args, 1); + arg1_gather[1] = GetArg32(args, 4); arg1 = Convert<uint64_t>(arg1_gather); std::array<uint32_t, 2> arg2_gather{}; - arg2_gather[0] = GetReg32(system, 5); - arg2_gather[1] = GetReg32(system, 6); + arg2_gather[0] = GetArg32(args, 5); + arg2_gather[1] = GetArg32(args, 6); arg2 = Convert<uint64_t>(arg2_gather); KernelDebug64From32(system, kern_debug_type, arg0, arg1, arg2); } -static void SvcWrap_ChangeKernelTraceState64From32(Core::System& system) { +static void SvcWrap_ChangeKernelTraceState64From32(Core::System& system, std::span<uint64_t, 8> args) { KernelTraceState kern_trace_state{}; - kern_trace_state = Convert<KernelTraceState>(GetReg32(system, 0)); + kern_trace_state = Convert<KernelTraceState>(GetArg32(args, 0)); ChangeKernelTraceState64From32(system, kern_trace_state); } -static void SvcWrap_CreateSession64From32(Core::System& system) { +static void SvcWrap_CreateSession64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_server_session_handle{}; @@ -947,31 +947,31 @@ static void SvcWrap_CreateSession64From32(Core::System& system) { bool is_light{}; uint32_t name{}; - is_light = Convert<bool>(GetReg32(system, 2)); - name = Convert<uint32_t>(GetReg32(system, 3)); + is_light = Convert<bool>(GetArg32(args, 2)); + name = Convert<uint32_t>(GetArg32(args, 3)); ret = CreateSession64From32(system, std::addressof(out_server_session_handle), std::addressof(out_client_session_handle), is_light, name); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_server_session_handle)); - SetReg32(system, 2, Convert<uint32_t>(out_client_session_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_server_session_handle)); + SetArg32(args, 2, Convert<uint32_t>(out_client_session_handle)); } -static void SvcWrap_AcceptSession64From32(Core::System& system) { +static void SvcWrap_AcceptSession64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; Handle port{}; - port = Convert<Handle>(GetReg32(system, 1)); + port = Convert<Handle>(GetArg32(args, 1)); ret = AcceptSession64From32(system, std::addressof(out_handle), port); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_ReplyAndReceive64From32(Core::System& system) { +static void SvcWrap_ReplyAndReceive64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_index{}; @@ -980,21 +980,21 @@ static void SvcWrap_ReplyAndReceive64From32(Core::System& system) { Handle reply_target{}; int64_t timeout_ns{}; - handles = Convert<uint32_t>(GetReg32(system, 1)); - num_handles = Convert<int32_t>(GetReg32(system, 2)); - reply_target = Convert<Handle>(GetReg32(system, 3)); + handles = Convert<uint32_t>(GetArg32(args, 1)); + num_handles = Convert<int32_t>(GetArg32(args, 2)); + reply_target = Convert<Handle>(GetArg32(args, 3)); std::array<uint32_t, 2> timeout_ns_gather{}; - timeout_ns_gather[0] = GetReg32(system, 0); - timeout_ns_gather[1] = GetReg32(system, 4); + timeout_ns_gather[0] = GetArg32(args, 0); + timeout_ns_gather[1] = GetArg32(args, 4); timeout_ns = Convert<int64_t>(timeout_ns_gather); ret = ReplyAndReceive64From32(system, std::addressof(out_index), handles, num_handles, reply_target, timeout_ns); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_index)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_index)); } -static void SvcWrap_ReplyAndReceiveWithUserBuffer64From32(Core::System& system) { +static void SvcWrap_ReplyAndReceiveWithUserBuffer64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_index{}; @@ -1005,23 +1005,23 @@ static void SvcWrap_ReplyAndReceiveWithUserBuffer64From32(Core::System& system) Handle reply_target{}; int64_t timeout_ns{}; - message_buffer = Convert<uint32_t>(GetReg32(system, 1)); - message_buffer_size = Convert<uint32_t>(GetReg32(system, 2)); - handles = Convert<uint32_t>(GetReg32(system, 3)); - num_handles = Convert<int32_t>(GetReg32(system, 0)); - reply_target = Convert<Handle>(GetReg32(system, 4)); + message_buffer = Convert<uint32_t>(GetArg32(args, 1)); + message_buffer_size = Convert<uint32_t>(GetArg32(args, 2)); + handles = Convert<uint32_t>(GetArg32(args, 3)); + num_handles = Convert<int32_t>(GetArg32(args, 0)); + reply_target = Convert<Handle>(GetArg32(args, 4)); std::array<uint32_t, 2> timeout_ns_gather{}; - timeout_ns_gather[0] = GetReg32(system, 5); - timeout_ns_gather[1] = GetReg32(system, 6); + timeout_ns_gather[0] = GetArg32(args, 5); + timeout_ns_gather[1] = GetArg32(args, 6); timeout_ns = Convert<int64_t>(timeout_ns_gather); ret = ReplyAndReceiveWithUserBuffer64From32(system, std::addressof(out_index), message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_index)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_index)); } -static void SvcWrap_CreateEvent64From32(Core::System& system) { +static void SvcWrap_CreateEvent64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_write_handle{}; @@ -1029,12 +1029,12 @@ static void SvcWrap_CreateEvent64From32(Core::System& system) { ret = CreateEvent64From32(system, std::addressof(out_write_handle), std::addressof(out_read_handle)); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_write_handle)); - SetReg32(system, 2, Convert<uint32_t>(out_read_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_write_handle)); + SetArg32(args, 2, Convert<uint32_t>(out_read_handle)); } -static void SvcWrap_MapIoRegion64From32(Core::System& system) { +static void SvcWrap_MapIoRegion64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle io_region{}; @@ -1042,89 +1042,89 @@ static void SvcWrap_MapIoRegion64From32(Core::System& system) { uint32_t size{}; MemoryPermission perm{}; - io_region = Convert<Handle>(GetReg32(system, 0)); - address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); - perm = Convert<MemoryPermission>(GetReg32(system, 3)); + io_region = Convert<Handle>(GetArg32(args, 0)); + address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); + perm = Convert<MemoryPermission>(GetArg32(args, 3)); ret = MapIoRegion64From32(system, io_region, address, size, perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapIoRegion64From32(Core::System& system) { +static void SvcWrap_UnmapIoRegion64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle io_region{}; uint32_t address{}; uint32_t size{}; - io_region = Convert<Handle>(GetReg32(system, 0)); - address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); + io_region = Convert<Handle>(GetArg32(args, 0)); + address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); ret = UnmapIoRegion64From32(system, io_region, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_MapPhysicalMemoryUnsafe64From32(Core::System& system) { +static void SvcWrap_MapPhysicalMemoryUnsafe64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; uint32_t size{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); ret = MapPhysicalMemoryUnsafe64From32(system, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapPhysicalMemoryUnsafe64From32(Core::System& system) { +static void SvcWrap_UnmapPhysicalMemoryUnsafe64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; uint32_t size{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); ret = UnmapPhysicalMemoryUnsafe64From32(system, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SetUnsafeLimit64From32(Core::System& system) { +static void SvcWrap_SetUnsafeLimit64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t limit{}; - limit = Convert<uint32_t>(GetReg32(system, 0)); + limit = Convert<uint32_t>(GetArg32(args, 0)); ret = SetUnsafeLimit64From32(system, limit); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_CreateCodeMemory64From32(Core::System& system) { +static void SvcWrap_CreateCodeMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; uint32_t address{}; uint32_t size{}; - address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); + address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); ret = CreateCodeMemory64From32(system, std::addressof(out_handle), address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_ControlCodeMemory64From32(Core::System& system) { +static void SvcWrap_ControlCodeMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle code_memory_handle{}; @@ -1133,28 +1133,28 @@ static void SvcWrap_ControlCodeMemory64From32(Core::System& system) { uint64_t size{}; MemoryPermission perm{}; - code_memory_handle = Convert<Handle>(GetReg32(system, 0)); - operation = Convert<CodeMemoryOperation>(GetReg32(system, 1)); + code_memory_handle = Convert<Handle>(GetArg32(args, 0)); + operation = Convert<CodeMemoryOperation>(GetArg32(args, 1)); std::array<uint32_t, 2> address_gather{}; - address_gather[0] = GetReg32(system, 2); - address_gather[1] = GetReg32(system, 3); + address_gather[0] = GetArg32(args, 2); + address_gather[1] = GetArg32(args, 3); address = Convert<uint64_t>(address_gather); std::array<uint32_t, 2> size_gather{}; - size_gather[0] = GetReg32(system, 4); - size_gather[1] = GetReg32(system, 5); + size_gather[0] = GetArg32(args, 4); + size_gather[1] = GetArg32(args, 5); size = Convert<uint64_t>(size_gather); - perm = Convert<MemoryPermission>(GetReg32(system, 6)); + perm = Convert<MemoryPermission>(GetArg32(args, 6)); ret = ControlCodeMemory64From32(system, code_memory_handle, operation, address, size, perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SleepSystem64From32(Core::System& system) { +static void SvcWrap_SleepSystem64From32(Core::System& system, std::span<uint64_t, 8> args) { SleepSystem64From32(system); } -static void SvcWrap_ReadWriteRegister64From32(Core::System& system) { +static void SvcWrap_ReadWriteRegister64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t out_value{}; @@ -1163,33 +1163,33 @@ static void SvcWrap_ReadWriteRegister64From32(Core::System& system) { uint32_t value{}; std::array<uint32_t, 2> address_gather{}; - address_gather[0] = GetReg32(system, 2); - address_gather[1] = GetReg32(system, 3); + address_gather[0] = GetArg32(args, 2); + address_gather[1] = GetArg32(args, 3); address = Convert<uint64_t>(address_gather); - mask = Convert<uint32_t>(GetReg32(system, 0)); - value = Convert<uint32_t>(GetReg32(system, 1)); + mask = Convert<uint32_t>(GetArg32(args, 0)); + value = Convert<uint32_t>(GetArg32(args, 1)); ret = ReadWriteRegister64From32(system, std::addressof(out_value), address, mask, value); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_value)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_value)); } -static void SvcWrap_SetProcessActivity64From32(Core::System& system) { +static void SvcWrap_SetProcessActivity64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; ProcessActivity process_activity{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); - process_activity = Convert<ProcessActivity>(GetReg32(system, 1)); + process_handle = Convert<Handle>(GetArg32(args, 0)); + process_activity = Convert<ProcessActivity>(GetArg32(args, 1)); ret = SetProcessActivity64From32(system, process_handle, process_activity); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_CreateSharedMemory64From32(Core::System& system) { +static void SvcWrap_CreateSharedMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -1197,17 +1197,17 @@ static void SvcWrap_CreateSharedMemory64From32(Core::System& system) { MemoryPermission owner_perm{}; MemoryPermission remote_perm{}; - size = Convert<uint32_t>(GetReg32(system, 1)); - owner_perm = Convert<MemoryPermission>(GetReg32(system, 2)); - remote_perm = Convert<MemoryPermission>(GetReg32(system, 3)); + size = Convert<uint32_t>(GetArg32(args, 1)); + owner_perm = Convert<MemoryPermission>(GetArg32(args, 2)); + remote_perm = Convert<MemoryPermission>(GetArg32(args, 3)); ret = CreateSharedMemory64From32(system, std::addressof(out_handle), size, owner_perm, remote_perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_MapTransferMemory64From32(Core::System& system) { +static void SvcWrap_MapTransferMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle trmem_handle{}; @@ -1215,67 +1215,67 @@ static void SvcWrap_MapTransferMemory64From32(Core::System& system) { uint32_t size{}; MemoryPermission owner_perm{}; - trmem_handle = Convert<Handle>(GetReg32(system, 0)); - address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); - owner_perm = Convert<MemoryPermission>(GetReg32(system, 3)); + trmem_handle = Convert<Handle>(GetArg32(args, 0)); + address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); + owner_perm = Convert<MemoryPermission>(GetArg32(args, 3)); ret = MapTransferMemory64From32(system, trmem_handle, address, size, owner_perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapTransferMemory64From32(Core::System& system) { +static void SvcWrap_UnmapTransferMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle trmem_handle{}; uint32_t address{}; uint32_t size{}; - trmem_handle = Convert<Handle>(GetReg32(system, 0)); - address = Convert<uint32_t>(GetReg32(system, 1)); - size = Convert<uint32_t>(GetReg32(system, 2)); + trmem_handle = Convert<Handle>(GetArg32(args, 0)); + address = Convert<uint32_t>(GetArg32(args, 1)); + size = Convert<uint32_t>(GetArg32(args, 2)); ret = UnmapTransferMemory64From32(system, trmem_handle, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_CreateInterruptEvent64From32(Core::System& system) { +static void SvcWrap_CreateInterruptEvent64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_read_handle{}; int32_t interrupt_id{}; InterruptType interrupt_type{}; - interrupt_id = Convert<int32_t>(GetReg32(system, 1)); - interrupt_type = Convert<InterruptType>(GetReg32(system, 2)); + interrupt_id = Convert<int32_t>(GetArg32(args, 1)); + interrupt_type = Convert<InterruptType>(GetArg32(args, 2)); ret = CreateInterruptEvent64From32(system, std::addressof(out_read_handle), interrupt_id, interrupt_type); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_read_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_read_handle)); } -static void SvcWrap_QueryPhysicalAddress64From32(Core::System& system) { +static void SvcWrap_QueryPhysicalAddress64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; ilp32::PhysicalMemoryInfo out_info{}; uint32_t address{}; - address = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetArg32(args, 1)); ret = QueryPhysicalAddress64From32(system, std::addressof(out_info), address); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_info_scatter = Convert<std::array<uint32_t, 4>>(out_info); - SetReg32(system, 1, out_info_scatter[0]); - SetReg32(system, 2, out_info_scatter[1]); - SetReg32(system, 3, out_info_scatter[2]); - SetReg32(system, 4, out_info_scatter[3]); + SetArg32(args, 1, out_info_scatter[0]); + SetArg32(args, 2, out_info_scatter[1]); + SetArg32(args, 3, out_info_scatter[2]); + SetArg32(args, 4, out_info_scatter[3]); } -static void SvcWrap_QueryIoMapping64From32(Core::System& system) { +static void SvcWrap_QueryIoMapping64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_address{}; @@ -1284,19 +1284,19 @@ static void SvcWrap_QueryIoMapping64From32(Core::System& system) { uint32_t size{}; std::array<uint32_t, 2> physical_address_gather{}; - physical_address_gather[0] = GetReg32(system, 2); - physical_address_gather[1] = GetReg32(system, 3); + physical_address_gather[0] = GetArg32(args, 2); + physical_address_gather[1] = GetArg32(args, 3); physical_address = Convert<uint64_t>(physical_address_gather); - size = Convert<uint32_t>(GetReg32(system, 0)); + size = Convert<uint32_t>(GetArg32(args, 0)); ret = QueryIoMapping64From32(system, std::addressof(out_address), std::addressof(out_size), physical_address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_address)); - SetReg32(system, 2, Convert<uint32_t>(out_size)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_address)); + SetArg32(args, 2, Convert<uint32_t>(out_size)); } -static void SvcWrap_CreateDeviceAddressSpace64From32(Core::System& system) { +static void SvcWrap_CreateDeviceAddressSpace64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -1304,49 +1304,49 @@ static void SvcWrap_CreateDeviceAddressSpace64From32(Core::System& system) { uint64_t das_size{}; std::array<uint32_t, 2> das_address_gather{}; - das_address_gather[0] = GetReg32(system, 2); - das_address_gather[1] = GetReg32(system, 3); + das_address_gather[0] = GetArg32(args, 2); + das_address_gather[1] = GetArg32(args, 3); das_address = Convert<uint64_t>(das_address_gather); std::array<uint32_t, 2> das_size_gather{}; - das_size_gather[0] = GetReg32(system, 0); - das_size_gather[1] = GetReg32(system, 1); + das_size_gather[0] = GetArg32(args, 0); + das_size_gather[1] = GetArg32(args, 1); das_size = Convert<uint64_t>(das_size_gather); ret = CreateDeviceAddressSpace64From32(system, std::addressof(out_handle), das_address, das_size); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_AttachDeviceAddressSpace64From32(Core::System& system) { +static void SvcWrap_AttachDeviceAddressSpace64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; DeviceName device_name{}; Handle das_handle{}; - device_name = Convert<DeviceName>(GetReg32(system, 0)); - das_handle = Convert<Handle>(GetReg32(system, 1)); + device_name = Convert<DeviceName>(GetArg32(args, 0)); + das_handle = Convert<Handle>(GetArg32(args, 1)); ret = AttachDeviceAddressSpace64From32(system, device_name, das_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_DetachDeviceAddressSpace64From32(Core::System& system) { +static void SvcWrap_DetachDeviceAddressSpace64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; DeviceName device_name{}; Handle das_handle{}; - device_name = Convert<DeviceName>(GetReg32(system, 0)); - das_handle = Convert<Handle>(GetReg32(system, 1)); + device_name = Convert<DeviceName>(GetArg32(args, 0)); + das_handle = Convert<Handle>(GetArg32(args, 1)); ret = DetachDeviceAddressSpace64From32(system, device_name, das_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_MapDeviceAddressSpaceByForce64From32(Core::System& system) { +static void SvcWrap_MapDeviceAddressSpaceByForce64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle das_handle{}; @@ -1356,25 +1356,25 @@ static void SvcWrap_MapDeviceAddressSpaceByForce64From32(Core::System& system) { uint64_t device_address{}; uint32_t option{}; - das_handle = Convert<Handle>(GetReg32(system, 0)); - process_handle = Convert<Handle>(GetReg32(system, 1)); + das_handle = Convert<Handle>(GetArg32(args, 0)); + process_handle = Convert<Handle>(GetArg32(args, 1)); std::array<uint32_t, 2> process_address_gather{}; - process_address_gather[0] = GetReg32(system, 2); - process_address_gather[1] = GetReg32(system, 3); + process_address_gather[0] = GetArg32(args, 2); + process_address_gather[1] = GetArg32(args, 3); process_address = Convert<uint64_t>(process_address_gather); - size = Convert<uint32_t>(GetReg32(system, 4)); + size = Convert<uint32_t>(GetArg32(args, 4)); std::array<uint32_t, 2> device_address_gather{}; - device_address_gather[0] = GetReg32(system, 5); - device_address_gather[1] = GetReg32(system, 6); + device_address_gather[0] = GetArg32(args, 5); + device_address_gather[1] = GetArg32(args, 6); device_address = Convert<uint64_t>(device_address_gather); - option = Convert<uint32_t>(GetReg32(system, 7)); + option = Convert<uint32_t>(GetArg32(args, 7)); ret = MapDeviceAddressSpaceByForce64From32(system, das_handle, process_handle, process_address, size, device_address, option); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_MapDeviceAddressSpaceAligned64From32(Core::System& system) { +static void SvcWrap_MapDeviceAddressSpaceAligned64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle das_handle{}; @@ -1384,25 +1384,25 @@ static void SvcWrap_MapDeviceAddressSpaceAligned64From32(Core::System& system) { uint64_t device_address{}; uint32_t option{}; - das_handle = Convert<Handle>(GetReg32(system, 0)); - process_handle = Convert<Handle>(GetReg32(system, 1)); + das_handle = Convert<Handle>(GetArg32(args, 0)); + process_handle = Convert<Handle>(GetArg32(args, 1)); std::array<uint32_t, 2> process_address_gather{}; - process_address_gather[0] = GetReg32(system, 2); - process_address_gather[1] = GetReg32(system, 3); + process_address_gather[0] = GetArg32(args, 2); + process_address_gather[1] = GetArg32(args, 3); process_address = Convert<uint64_t>(process_address_gather); - size = Convert<uint32_t>(GetReg32(system, 4)); + size = Convert<uint32_t>(GetArg32(args, 4)); std::array<uint32_t, 2> device_address_gather{}; - device_address_gather[0] = GetReg32(system, 5); - device_address_gather[1] = GetReg32(system, 6); + device_address_gather[0] = GetArg32(args, 5); + device_address_gather[1] = GetArg32(args, 6); device_address = Convert<uint64_t>(device_address_gather); - option = Convert<uint32_t>(GetReg32(system, 7)); + option = Convert<uint32_t>(GetArg32(args, 7)); ret = MapDeviceAddressSpaceAligned64From32(system, das_handle, process_handle, process_address, size, device_address, option); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapDeviceAddressSpace64From32(Core::System& system) { +static void SvcWrap_UnmapDeviceAddressSpace64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle das_handle{}; @@ -1411,145 +1411,145 @@ static void SvcWrap_UnmapDeviceAddressSpace64From32(Core::System& system) { uint32_t size{}; uint64_t device_address{}; - das_handle = Convert<Handle>(GetReg32(system, 0)); - process_handle = Convert<Handle>(GetReg32(system, 1)); + das_handle = Convert<Handle>(GetArg32(args, 0)); + process_handle = Convert<Handle>(GetArg32(args, 1)); std::array<uint32_t, 2> process_address_gather{}; - process_address_gather[0] = GetReg32(system, 2); - process_address_gather[1] = GetReg32(system, 3); + process_address_gather[0] = GetArg32(args, 2); + process_address_gather[1] = GetArg32(args, 3); process_address = Convert<uint64_t>(process_address_gather); - size = Convert<uint32_t>(GetReg32(system, 4)); + size = Convert<uint32_t>(GetArg32(args, 4)); std::array<uint32_t, 2> device_address_gather{}; - device_address_gather[0] = GetReg32(system, 5); - device_address_gather[1] = GetReg32(system, 6); + device_address_gather[0] = GetArg32(args, 5); + device_address_gather[1] = GetArg32(args, 6); device_address = Convert<uint64_t>(device_address_gather); ret = UnmapDeviceAddressSpace64From32(system, das_handle, process_handle, process_address, size, device_address); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_InvalidateProcessDataCache64From32(Core::System& system) { +static void SvcWrap_InvalidateProcessDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; uint64_t address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetArg32(args, 0)); std::array<uint32_t, 2> address_gather{}; - address_gather[0] = GetReg32(system, 2); - address_gather[1] = GetReg32(system, 3); + address_gather[0] = GetArg32(args, 2); + address_gather[1] = GetArg32(args, 3); address = Convert<uint64_t>(address_gather); std::array<uint32_t, 2> size_gather{}; - size_gather[0] = GetReg32(system, 1); - size_gather[1] = GetReg32(system, 4); + size_gather[0] = GetArg32(args, 1); + size_gather[1] = GetArg32(args, 4); size = Convert<uint64_t>(size_gather); ret = InvalidateProcessDataCache64From32(system, process_handle, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_StoreProcessDataCache64From32(Core::System& system) { +static void SvcWrap_StoreProcessDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; uint64_t address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetArg32(args, 0)); std::array<uint32_t, 2> address_gather{}; - address_gather[0] = GetReg32(system, 2); - address_gather[1] = GetReg32(system, 3); + address_gather[0] = GetArg32(args, 2); + address_gather[1] = GetArg32(args, 3); address = Convert<uint64_t>(address_gather); std::array<uint32_t, 2> size_gather{}; - size_gather[0] = GetReg32(system, 1); - size_gather[1] = GetReg32(system, 4); + size_gather[0] = GetArg32(args, 1); + size_gather[1] = GetArg32(args, 4); size = Convert<uint64_t>(size_gather); ret = StoreProcessDataCache64From32(system, process_handle, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_FlushProcessDataCache64From32(Core::System& system) { +static void SvcWrap_FlushProcessDataCache64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; uint64_t address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetArg32(args, 0)); std::array<uint32_t, 2> address_gather{}; - address_gather[0] = GetReg32(system, 2); - address_gather[1] = GetReg32(system, 3); + address_gather[0] = GetArg32(args, 2); + address_gather[1] = GetArg32(args, 3); address = Convert<uint64_t>(address_gather); std::array<uint32_t, 2> size_gather{}; - size_gather[0] = GetReg32(system, 1); - size_gather[1] = GetReg32(system, 4); + size_gather[0] = GetArg32(args, 1); + size_gather[1] = GetArg32(args, 4); size = Convert<uint64_t>(size_gather); ret = FlushProcessDataCache64From32(system, process_handle, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_DebugActiveProcess64From32(Core::System& system) { +static void SvcWrap_DebugActiveProcess64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; uint64_t process_id{}; std::array<uint32_t, 2> process_id_gather{}; - process_id_gather[0] = GetReg32(system, 2); - process_id_gather[1] = GetReg32(system, 3); + process_id_gather[0] = GetArg32(args, 2); + process_id_gather[1] = GetArg32(args, 3); process_id = Convert<uint64_t>(process_id_gather); ret = DebugActiveProcess64From32(system, std::addressof(out_handle), process_id); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_BreakDebugProcess64From32(Core::System& system) { +static void SvcWrap_BreakDebugProcess64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; - debug_handle = Convert<Handle>(GetReg32(system, 0)); + debug_handle = Convert<Handle>(GetArg32(args, 0)); ret = BreakDebugProcess64From32(system, debug_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_TerminateDebugProcess64From32(Core::System& system) { +static void SvcWrap_TerminateDebugProcess64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; - debug_handle = Convert<Handle>(GetReg32(system, 0)); + debug_handle = Convert<Handle>(GetArg32(args, 0)); ret = TerminateDebugProcess64From32(system, debug_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_GetDebugEvent64From32(Core::System& system) { +static void SvcWrap_GetDebugEvent64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t out_info{}; Handle debug_handle{}; - out_info = Convert<uint32_t>(GetReg32(system, 0)); - debug_handle = Convert<Handle>(GetReg32(system, 1)); + out_info = Convert<uint32_t>(GetArg32(args, 0)); + debug_handle = Convert<Handle>(GetArg32(args, 1)); ret = GetDebugEvent64From32(system, out_info, debug_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_ContinueDebugEvent64From32(Core::System& system) { +static void SvcWrap_ContinueDebugEvent64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; @@ -1557,33 +1557,33 @@ static void SvcWrap_ContinueDebugEvent64From32(Core::System& system) { uint32_t thread_ids{}; int32_t num_thread_ids{}; - debug_handle = Convert<Handle>(GetReg32(system, 0)); - flags = Convert<uint32_t>(GetReg32(system, 1)); - thread_ids = Convert<uint32_t>(GetReg32(system, 2)); - num_thread_ids = Convert<int32_t>(GetReg32(system, 3)); + debug_handle = Convert<Handle>(GetArg32(args, 0)); + flags = Convert<uint32_t>(GetArg32(args, 1)); + thread_ids = Convert<uint32_t>(GetArg32(args, 2)); + num_thread_ids = Convert<int32_t>(GetArg32(args, 3)); ret = ContinueDebugEvent64From32(system, debug_handle, flags, thread_ids, num_thread_ids); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_GetProcessList64From32(Core::System& system) { +static void SvcWrap_GetProcessList64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_num_processes{}; uint32_t out_process_ids{}; int32_t max_out_count{}; - out_process_ids = Convert<uint32_t>(GetReg32(system, 1)); - max_out_count = Convert<int32_t>(GetReg32(system, 2)); + out_process_ids = Convert<uint32_t>(GetArg32(args, 1)); + max_out_count = Convert<int32_t>(GetArg32(args, 2)); ret = GetProcessList64From32(system, std::addressof(out_num_processes), out_process_ids, max_out_count); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_num_processes)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_num_processes)); } -static void SvcWrap_GetThreadList64From32(Core::System& system) { +static void SvcWrap_GetThreadList64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_num_threads{}; @@ -1591,17 +1591,17 @@ static void SvcWrap_GetThreadList64From32(Core::System& system) { int32_t max_out_count{}; Handle debug_handle{}; - out_thread_ids = Convert<uint32_t>(GetReg32(system, 1)); - max_out_count = Convert<int32_t>(GetReg32(system, 2)); - debug_handle = Convert<Handle>(GetReg32(system, 3)); + out_thread_ids = Convert<uint32_t>(GetArg32(args, 1)); + max_out_count = Convert<int32_t>(GetArg32(args, 2)); + debug_handle = Convert<Handle>(GetArg32(args, 3)); ret = GetThreadList64From32(system, std::addressof(out_num_threads), out_thread_ids, max_out_count, debug_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_num_threads)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_num_threads)); } -static void SvcWrap_GetDebugThreadContext64From32(Core::System& system) { +static void SvcWrap_GetDebugThreadContext64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t out_context{}; @@ -1609,20 +1609,20 @@ static void SvcWrap_GetDebugThreadContext64From32(Core::System& system) { uint64_t thread_id{}; uint32_t context_flags{}; - out_context = Convert<uint32_t>(GetReg32(system, 0)); - debug_handle = Convert<Handle>(GetReg32(system, 1)); + out_context = Convert<uint32_t>(GetArg32(args, 0)); + debug_handle = Convert<Handle>(GetArg32(args, 1)); std::array<uint32_t, 2> thread_id_gather{}; - thread_id_gather[0] = GetReg32(system, 2); - thread_id_gather[1] = GetReg32(system, 3); + thread_id_gather[0] = GetArg32(args, 2); + thread_id_gather[1] = GetArg32(args, 3); thread_id = Convert<uint64_t>(thread_id_gather); - context_flags = Convert<uint32_t>(GetReg32(system, 4)); + context_flags = Convert<uint32_t>(GetArg32(args, 4)); ret = GetDebugThreadContext64From32(system, out_context, debug_handle, thread_id, context_flags); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SetDebugThreadContext64From32(Core::System& system) { +static void SvcWrap_SetDebugThreadContext64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; @@ -1630,20 +1630,20 @@ static void SvcWrap_SetDebugThreadContext64From32(Core::System& system) { uint32_t context{}; uint32_t context_flags{}; - debug_handle = Convert<Handle>(GetReg32(system, 0)); + debug_handle = Convert<Handle>(GetArg32(args, 0)); std::array<uint32_t, 2> thread_id_gather{}; - thread_id_gather[0] = GetReg32(system, 2); - thread_id_gather[1] = GetReg32(system, 3); + thread_id_gather[0] = GetArg32(args, 2); + thread_id_gather[1] = GetArg32(args, 3); thread_id = Convert<uint64_t>(thread_id_gather); - context = Convert<uint32_t>(GetReg32(system, 1)); - context_flags = Convert<uint32_t>(GetReg32(system, 4)); + context = Convert<uint32_t>(GetArg32(args, 1)); + context_flags = Convert<uint32_t>(GetArg32(args, 4)); ret = SetDebugThreadContext64From32(system, debug_handle, thread_id, context, context_flags); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_QueryDebugProcessMemory64From32(Core::System& system) { +static void SvcWrap_QueryDebugProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; PageInfo out_page_info{}; @@ -1651,17 +1651,17 @@ static void SvcWrap_QueryDebugProcessMemory64From32(Core::System& system) { Handle process_handle{}; uint32_t address{}; - out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); - process_handle = Convert<Handle>(GetReg32(system, 2)); - address = Convert<uint32_t>(GetReg32(system, 3)); + out_memory_info = Convert<uint32_t>(GetArg32(args, 0)); + process_handle = Convert<Handle>(GetArg32(args, 2)); + address = Convert<uint32_t>(GetArg32(args, 3)); ret = QueryDebugProcessMemory64From32(system, out_memory_info, std::addressof(out_page_info), process_handle, address); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_page_info)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_page_info)); } -static void SvcWrap_ReadDebugProcessMemory64From32(Core::System& system) { +static void SvcWrap_ReadDebugProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t buffer{}; @@ -1669,17 +1669,17 @@ static void SvcWrap_ReadDebugProcessMemory64From32(Core::System& system) { uint32_t address{}; uint32_t size{}; - buffer = Convert<uint32_t>(GetReg32(system, 0)); - debug_handle = Convert<Handle>(GetReg32(system, 1)); - address = Convert<uint32_t>(GetReg32(system, 2)); - size = Convert<uint32_t>(GetReg32(system, 3)); + buffer = Convert<uint32_t>(GetArg32(args, 0)); + debug_handle = Convert<Handle>(GetArg32(args, 1)); + address = Convert<uint32_t>(GetArg32(args, 2)); + size = Convert<uint32_t>(GetArg32(args, 3)); ret = ReadDebugProcessMemory64From32(system, buffer, debug_handle, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_WriteDebugProcessMemory64From32(Core::System& system) { +static void SvcWrap_WriteDebugProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; @@ -1687,39 +1687,39 @@ static void SvcWrap_WriteDebugProcessMemory64From32(Core::System& system) { uint32_t address{}; uint32_t size{}; - debug_handle = Convert<Handle>(GetReg32(system, 0)); - buffer = Convert<uint32_t>(GetReg32(system, 1)); - address = Convert<uint32_t>(GetReg32(system, 2)); - size = Convert<uint32_t>(GetReg32(system, 3)); + debug_handle = Convert<Handle>(GetArg32(args, 0)); + buffer = Convert<uint32_t>(GetArg32(args, 1)); + address = Convert<uint32_t>(GetArg32(args, 2)); + size = Convert<uint32_t>(GetArg32(args, 3)); ret = WriteDebugProcessMemory64From32(system, debug_handle, buffer, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SetHardwareBreakPoint64From32(Core::System& system) { +static void SvcWrap_SetHardwareBreakPoint64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; HardwareBreakPointRegisterName name{}; uint64_t flags{}; uint64_t value{}; - name = Convert<HardwareBreakPointRegisterName>(GetReg32(system, 0)); + name = Convert<HardwareBreakPointRegisterName>(GetArg32(args, 0)); std::array<uint32_t, 2> flags_gather{}; - flags_gather[0] = GetReg32(system, 2); - flags_gather[1] = GetReg32(system, 3); + flags_gather[0] = GetArg32(args, 2); + flags_gather[1] = GetArg32(args, 3); flags = Convert<uint64_t>(flags_gather); std::array<uint32_t, 2> value_gather{}; - value_gather[0] = GetReg32(system, 1); - value_gather[1] = GetReg32(system, 4); + value_gather[0] = GetArg32(args, 1); + value_gather[1] = GetArg32(args, 4); value = Convert<uint64_t>(value_gather); ret = SetHardwareBreakPoint64From32(system, name, flags, value); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_GetDebugThreadParam64From32(Core::System& system) { +static void SvcWrap_GetDebugThreadParam64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_64{}; @@ -1728,23 +1728,23 @@ static void SvcWrap_GetDebugThreadParam64From32(Core::System& system) { uint64_t thread_id{}; DebugThreadParam param{}; - debug_handle = Convert<Handle>(GetReg32(system, 2)); + debug_handle = Convert<Handle>(GetArg32(args, 2)); std::array<uint32_t, 2> thread_id_gather{}; - thread_id_gather[0] = GetReg32(system, 0); - thread_id_gather[1] = GetReg32(system, 1); + thread_id_gather[0] = GetArg32(args, 0); + thread_id_gather[1] = GetArg32(args, 1); thread_id = Convert<uint64_t>(thread_id_gather); - param = Convert<DebugThreadParam>(GetReg32(system, 3)); + param = Convert<DebugThreadParam>(GetArg32(args, 3)); ret = GetDebugThreadParam64From32(system, std::addressof(out_64), std::addressof(out_32), debug_handle, thread_id, param); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_64_scatter = Convert<std::array<uint32_t, 2>>(out_64); - SetReg32(system, 1, out_64_scatter[0]); - SetReg32(system, 2, out_64_scatter[1]); - SetReg32(system, 3, Convert<uint32_t>(out_32)); + SetArg32(args, 1, out_64_scatter[0]); + SetArg32(args, 2, out_64_scatter[1]); + SetArg32(args, 3, Convert<uint32_t>(out_32)); } -static void SvcWrap_GetSystemInfo64From32(Core::System& system) { +static void SvcWrap_GetSystemInfo64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out{}; @@ -1752,22 +1752,22 @@ static void SvcWrap_GetSystemInfo64From32(Core::System& system) { Handle handle{}; uint64_t info_subtype{}; - info_type = Convert<SystemInfoType>(GetReg32(system, 1)); - handle = Convert<Handle>(GetReg32(system, 2)); + info_type = Convert<SystemInfoType>(GetArg32(args, 1)); + handle = Convert<Handle>(GetArg32(args, 2)); std::array<uint32_t, 2> info_subtype_gather{}; - info_subtype_gather[0] = GetReg32(system, 0); - info_subtype_gather[1] = GetReg32(system, 3); + info_subtype_gather[0] = GetArg32(args, 0); + info_subtype_gather[1] = GetArg32(args, 3); info_subtype = Convert<uint64_t>(info_subtype_gather); ret = GetSystemInfo64From32(system, std::addressof(out), info_type, handle, info_subtype); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_scatter = Convert<std::array<uint32_t, 2>>(out); - SetReg32(system, 1, out_scatter[0]); - SetReg32(system, 2, out_scatter[1]); + SetArg32(args, 1, out_scatter[0]); + SetArg32(args, 2, out_scatter[1]); } -static void SvcWrap_CreatePort64From32(Core::System& system) { +static void SvcWrap_CreatePort64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_server_handle{}; @@ -1776,48 +1776,48 @@ static void SvcWrap_CreatePort64From32(Core::System& system) { bool is_light{}; uint32_t name{}; - max_sessions = Convert<int32_t>(GetReg32(system, 2)); - is_light = Convert<bool>(GetReg32(system, 3)); - name = Convert<uint32_t>(GetReg32(system, 0)); + max_sessions = Convert<int32_t>(GetArg32(args, 2)); + is_light = Convert<bool>(GetArg32(args, 3)); + name = Convert<uint32_t>(GetArg32(args, 0)); ret = CreatePort64From32(system, std::addressof(out_server_handle), std::addressof(out_client_handle), max_sessions, is_light, name); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_server_handle)); - SetReg32(system, 2, Convert<uint32_t>(out_client_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_server_handle)); + SetArg32(args, 2, Convert<uint32_t>(out_client_handle)); } -static void SvcWrap_ManageNamedPort64From32(Core::System& system) { +static void SvcWrap_ManageNamedPort64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_server_handle{}; uint32_t name{}; int32_t max_sessions{}; - name = Convert<uint32_t>(GetReg32(system, 1)); - max_sessions = Convert<int32_t>(GetReg32(system, 2)); + name = Convert<uint32_t>(GetArg32(args, 1)); + max_sessions = Convert<int32_t>(GetArg32(args, 2)); ret = ManageNamedPort64From32(system, std::addressof(out_server_handle), name, max_sessions); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_server_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_server_handle)); } -static void SvcWrap_ConnectToPort64From32(Core::System& system) { +static void SvcWrap_ConnectToPort64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; Handle port{}; - port = Convert<Handle>(GetReg32(system, 1)); + port = Convert<Handle>(GetArg32(args, 1)); ret = ConnectToPort64From32(system, std::addressof(out_handle), port); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system) { +static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; @@ -1825,23 +1825,23 @@ static void SvcWrap_SetProcessMemoryPermission64From32(Core::System& system) { uint64_t size{}; MemoryPermission perm{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetArg32(args, 0)); std::array<uint32_t, 2> address_gather{}; - address_gather[0] = GetReg32(system, 2); - address_gather[1] = GetReg32(system, 3); + address_gather[0] = GetArg32(args, 2); + address_gather[1] = GetArg32(args, 3); address = Convert<uint64_t>(address_gather); std::array<uint32_t, 2> size_gather{}; - size_gather[0] = GetReg32(system, 1); - size_gather[1] = GetReg32(system, 4); + size_gather[0] = GetArg32(args, 1); + size_gather[1] = GetArg32(args, 4); size = Convert<uint64_t>(size_gather); - perm = Convert<MemoryPermission>(GetReg32(system, 5)); + perm = Convert<MemoryPermission>(GetArg32(args, 5)); ret = SetProcessMemoryPermission64From32(system, process_handle, address, size, perm); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_MapProcessMemory64From32(Core::System& system) { +static void SvcWrap_MapProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t dst_address{}; @@ -1849,20 +1849,20 @@ static void SvcWrap_MapProcessMemory64From32(Core::System& system) { uint64_t src_address{}; uint32_t size{}; - dst_address = Convert<uint32_t>(GetReg32(system, 0)); - process_handle = Convert<Handle>(GetReg32(system, 1)); + dst_address = Convert<uint32_t>(GetArg32(args, 0)); + process_handle = Convert<Handle>(GetArg32(args, 1)); std::array<uint32_t, 2> src_address_gather{}; - src_address_gather[0] = GetReg32(system, 2); - src_address_gather[1] = GetReg32(system, 3); + src_address_gather[0] = GetArg32(args, 2); + src_address_gather[1] = GetArg32(args, 3); src_address = Convert<uint64_t>(src_address_gather); - size = Convert<uint32_t>(GetReg32(system, 4)); + size = Convert<uint32_t>(GetArg32(args, 4)); ret = MapProcessMemory64From32(system, dst_address, process_handle, src_address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapProcessMemory64From32(Core::System& system) { +static void SvcWrap_UnmapProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t dst_address{}; @@ -1870,20 +1870,20 @@ static void SvcWrap_UnmapProcessMemory64From32(Core::System& system) { uint64_t src_address{}; uint32_t size{}; - dst_address = Convert<uint32_t>(GetReg32(system, 0)); - process_handle = Convert<Handle>(GetReg32(system, 1)); + dst_address = Convert<uint32_t>(GetArg32(args, 0)); + process_handle = Convert<Handle>(GetArg32(args, 1)); std::array<uint32_t, 2> src_address_gather{}; - src_address_gather[0] = GetReg32(system, 2); - src_address_gather[1] = GetReg32(system, 3); + src_address_gather[0] = GetArg32(args, 2); + src_address_gather[1] = GetArg32(args, 3); src_address = Convert<uint64_t>(src_address_gather); - size = Convert<uint32_t>(GetReg32(system, 4)); + size = Convert<uint32_t>(GetArg32(args, 4)); ret = UnmapProcessMemory64From32(system, dst_address, process_handle, src_address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_QueryProcessMemory64From32(Core::System& system) { +static void SvcWrap_QueryProcessMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; PageInfo out_page_info{}; @@ -1891,20 +1891,20 @@ static void SvcWrap_QueryProcessMemory64From32(Core::System& system) { Handle process_handle{}; uint64_t address{}; - out_memory_info = Convert<uint32_t>(GetReg32(system, 0)); - process_handle = Convert<Handle>(GetReg32(system, 2)); + out_memory_info = Convert<uint32_t>(GetArg32(args, 0)); + process_handle = Convert<Handle>(GetArg32(args, 2)); std::array<uint32_t, 2> address_gather{}; - address_gather[0] = GetReg32(system, 1); - address_gather[1] = GetReg32(system, 3); + address_gather[0] = GetArg32(args, 1); + address_gather[1] = GetArg32(args, 3); address = Convert<uint64_t>(address_gather); ret = QueryProcessMemory64From32(system, out_memory_info, std::addressof(out_page_info), process_handle, address); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_page_info)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_page_info)); } -static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system) { +static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; @@ -1912,26 +1912,26 @@ static void SvcWrap_MapProcessCodeMemory64From32(Core::System& system) { uint64_t src_address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetArg32(args, 0)); std::array<uint32_t, 2> dst_address_gather{}; - dst_address_gather[0] = GetReg32(system, 2); - dst_address_gather[1] = GetReg32(system, 3); + dst_address_gather[0] = GetArg32(args, 2); + dst_address_gather[1] = GetArg32(args, 3); dst_address = Convert<uint64_t>(dst_address_gather); std::array<uint32_t, 2> src_address_gather{}; - src_address_gather[0] = GetReg32(system, 1); - src_address_gather[1] = GetReg32(system, 4); + src_address_gather[0] = GetArg32(args, 1); + src_address_gather[1] = GetArg32(args, 4); src_address = Convert<uint64_t>(src_address_gather); std::array<uint32_t, 2> size_gather{}; - size_gather[0] = GetReg32(system, 5); - size_gather[1] = GetReg32(system, 6); + size_gather[0] = GetArg32(args, 5); + size_gather[1] = GetArg32(args, 6); size = Convert<uint64_t>(size_gather); ret = MapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system) { +static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; @@ -1939,26 +1939,26 @@ static void SvcWrap_UnmapProcessCodeMemory64From32(Core::System& system) { uint64_t src_address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetArg32(args, 0)); std::array<uint32_t, 2> dst_address_gather{}; - dst_address_gather[0] = GetReg32(system, 2); - dst_address_gather[1] = GetReg32(system, 3); + dst_address_gather[0] = GetArg32(args, 2); + dst_address_gather[1] = GetArg32(args, 3); dst_address = Convert<uint64_t>(dst_address_gather); std::array<uint32_t, 2> src_address_gather{}; - src_address_gather[0] = GetReg32(system, 1); - src_address_gather[1] = GetReg32(system, 4); + src_address_gather[0] = GetArg32(args, 1); + src_address_gather[1] = GetArg32(args, 4); src_address = Convert<uint64_t>(src_address_gather); std::array<uint32_t, 2> size_gather{}; - size_gather[0] = GetReg32(system, 5); - size_gather[1] = GetReg32(system, 6); + size_gather[0] = GetArg32(args, 5); + size_gather[1] = GetArg32(args, 6); size = Convert<uint64_t>(size_gather); ret = UnmapProcessCodeMemory64From32(system, process_handle, dst_address, src_address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_CreateProcess64From32(Core::System& system) { +static void SvcWrap_CreateProcess64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -1966,17 +1966,17 @@ static void SvcWrap_CreateProcess64From32(Core::System& system) { uint32_t caps{}; int32_t num_caps{}; - parameters = Convert<uint32_t>(GetReg32(system, 1)); - caps = Convert<uint32_t>(GetReg32(system, 2)); - num_caps = Convert<int32_t>(GetReg32(system, 3)); + parameters = Convert<uint32_t>(GetArg32(args, 1)); + caps = Convert<uint32_t>(GetArg32(args, 2)); + num_caps = Convert<int32_t>(GetArg32(args, 3)); ret = CreateProcess64From32(system, std::addressof(out_handle), parameters, caps, num_caps); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_StartProcess64From32(Core::System& system) { +static void SvcWrap_StartProcess64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; @@ -1984,138 +1984,138 @@ static void SvcWrap_StartProcess64From32(Core::System& system) { int32_t core_id{}; uint64_t main_thread_stack_size{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); - priority = Convert<int32_t>(GetReg32(system, 1)); - core_id = Convert<int32_t>(GetReg32(system, 2)); + process_handle = Convert<Handle>(GetArg32(args, 0)); + priority = Convert<int32_t>(GetArg32(args, 1)); + core_id = Convert<int32_t>(GetArg32(args, 2)); std::array<uint32_t, 2> main_thread_stack_size_gather{}; - main_thread_stack_size_gather[0] = GetReg32(system, 3); - main_thread_stack_size_gather[1] = GetReg32(system, 4); + main_thread_stack_size_gather[0] = GetArg32(args, 3); + main_thread_stack_size_gather[1] = GetArg32(args, 4); main_thread_stack_size = Convert<uint64_t>(main_thread_stack_size_gather); ret = StartProcess64From32(system, process_handle, priority, core_id, main_thread_stack_size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_TerminateProcess64From32(Core::System& system) { +static void SvcWrap_TerminateProcess64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; - process_handle = Convert<Handle>(GetReg32(system, 0)); + process_handle = Convert<Handle>(GetArg32(args, 0)); ret = TerminateProcess64From32(system, process_handle); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_GetProcessInfo64From32(Core::System& system) { +static void SvcWrap_GetProcessInfo64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int64_t out_info{}; Handle process_handle{}; ProcessInfoType info_type{}; - process_handle = Convert<Handle>(GetReg32(system, 1)); - info_type = Convert<ProcessInfoType>(GetReg32(system, 2)); + process_handle = Convert<Handle>(GetArg32(args, 1)); + info_type = Convert<ProcessInfoType>(GetArg32(args, 2)); ret = GetProcessInfo64From32(system, std::addressof(out_info), process_handle, info_type); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); auto out_info_scatter = Convert<std::array<uint32_t, 2>>(out_info); - SetReg32(system, 1, out_info_scatter[0]); - SetReg32(system, 2, out_info_scatter[1]); + SetArg32(args, 1, out_info_scatter[0]); + SetArg32(args, 2, out_info_scatter[1]); } -static void SvcWrap_CreateResourceLimit64From32(Core::System& system) { +static void SvcWrap_CreateResourceLimit64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; ret = CreateResourceLimit64From32(system, std::addressof(out_handle)); - SetReg32(system, 0, Convert<uint32_t>(ret)); - SetReg32(system, 1, Convert<uint32_t>(out_handle)); + SetArg32(args, 0, Convert<uint32_t>(ret)); + SetArg32(args, 1, Convert<uint32_t>(out_handle)); } -static void SvcWrap_SetResourceLimitLimitValue64From32(Core::System& system) { +static void SvcWrap_SetResourceLimitLimitValue64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle resource_limit_handle{}; LimitableResource which{}; int64_t limit_value{}; - resource_limit_handle = Convert<Handle>(GetReg32(system, 0)); - which = Convert<LimitableResource>(GetReg32(system, 1)); + resource_limit_handle = Convert<Handle>(GetArg32(args, 0)); + which = Convert<LimitableResource>(GetArg32(args, 1)); std::array<uint32_t, 2> limit_value_gather{}; - limit_value_gather[0] = GetReg32(system, 2); - limit_value_gather[1] = GetReg32(system, 3); + limit_value_gather[0] = GetArg32(args, 2); + limit_value_gather[1] = GetArg32(args, 3); limit_value = Convert<int64_t>(limit_value_gather); ret = SetResourceLimitLimitValue64From32(system, resource_limit_handle, which, limit_value); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_MapInsecureMemory64From32(Core::System& system) { +static void SvcWrap_MapInsecureMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; uint32_t size{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); ret = MapInsecureMemory64From32(system, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_UnmapInsecureMemory64From32(Core::System& system) { +static void SvcWrap_UnmapInsecureMemory64From32(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t address{}; uint32_t size{}; - address = Convert<uint32_t>(GetReg32(system, 0)); - size = Convert<uint32_t>(GetReg32(system, 1)); + address = Convert<uint32_t>(GetArg32(args, 0)); + size = Convert<uint32_t>(GetArg32(args, 1)); ret = UnmapInsecureMemory64From32(system, address, size); - SetReg32(system, 0, Convert<uint32_t>(ret)); + SetArg32(args, 0, Convert<uint32_t>(ret)); } -static void SvcWrap_SetHeapSize64(Core::System& system) { +static void SvcWrap_SetHeapSize64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_address{}; uint64_t size{}; - size = Convert<uint64_t>(GetReg64(system, 1)); + size = Convert<uint64_t>(GetArg64(args, 1)); ret = SetHeapSize64(system, std::addressof(out_address), size); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_address)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_address)); } -static void SvcWrap_SetMemoryPermission64(Core::System& system) { +static void SvcWrap_SetMemoryPermission64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; uint64_t size{}; MemoryPermission perm{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); - perm = Convert<MemoryPermission>(GetReg64(system, 2)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); + perm = Convert<MemoryPermission>(GetArg64(args, 2)); ret = SetMemoryPermission64(system, address, size, perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SetMemoryAttribute64(Core::System& system) { +static void SvcWrap_SetMemoryAttribute64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; @@ -2123,69 +2123,69 @@ static void SvcWrap_SetMemoryAttribute64(Core::System& system) { uint32_t mask{}; uint32_t attr{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); - mask = Convert<uint32_t>(GetReg64(system, 2)); - attr = Convert<uint32_t>(GetReg64(system, 3)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); + mask = Convert<uint32_t>(GetArg64(args, 2)); + attr = Convert<uint32_t>(GetArg64(args, 3)); ret = SetMemoryAttribute64(system, address, size, mask, attr); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_MapMemory64(Core::System& system) { +static void SvcWrap_MapMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t dst_address{}; uint64_t src_address{}; uint64_t size{}; - dst_address = Convert<uint64_t>(GetReg64(system, 0)); - src_address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + dst_address = Convert<uint64_t>(GetArg64(args, 0)); + src_address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = MapMemory64(system, dst_address, src_address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapMemory64(Core::System& system) { +static void SvcWrap_UnmapMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t dst_address{}; uint64_t src_address{}; uint64_t size{}; - dst_address = Convert<uint64_t>(GetReg64(system, 0)); - src_address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + dst_address = Convert<uint64_t>(GetArg64(args, 0)); + src_address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = UnmapMemory64(system, dst_address, src_address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_QueryMemory64(Core::System& system) { +static void SvcWrap_QueryMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; PageInfo out_page_info{}; uint64_t out_memory_info{}; uint64_t address{}; - out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 2)); + out_memory_info = Convert<uint64_t>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 2)); ret = QueryMemory64(system, out_memory_info, std::addressof(out_page_info), address); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_page_info)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_page_info)); } -static void SvcWrap_ExitProcess64(Core::System& system) { +static void SvcWrap_ExitProcess64(Core::System& system, std::span<uint64_t, 8> args) { ExitProcess64(system); } -static void SvcWrap_CreateThread64(Core::System& system) { +static void SvcWrap_CreateThread64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -2195,135 +2195,135 @@ static void SvcWrap_CreateThread64(Core::System& system) { int32_t priority{}; int32_t core_id{}; - func = Convert<uint64_t>(GetReg64(system, 1)); - arg = Convert<uint64_t>(GetReg64(system, 2)); - stack_bottom = Convert<uint64_t>(GetReg64(system, 3)); - priority = Convert<int32_t>(GetReg64(system, 4)); - core_id = Convert<int32_t>(GetReg64(system, 5)); + func = Convert<uint64_t>(GetArg64(args, 1)); + arg = Convert<uint64_t>(GetArg64(args, 2)); + stack_bottom = Convert<uint64_t>(GetArg64(args, 3)); + priority = Convert<int32_t>(GetArg64(args, 4)); + core_id = Convert<int32_t>(GetArg64(args, 5)); ret = CreateThread64(system, std::addressof(out_handle), func, arg, stack_bottom, priority, core_id); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_StartThread64(Core::System& system) { +static void SvcWrap_StartThread64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; - thread_handle = Convert<Handle>(GetReg64(system, 0)); + thread_handle = Convert<Handle>(GetArg64(args, 0)); ret = StartThread64(system, thread_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_ExitThread64(Core::System& system) { +static void SvcWrap_ExitThread64(Core::System& system, std::span<uint64_t, 8> args) { ExitThread64(system); } -static void SvcWrap_SleepThread64(Core::System& system) { +static void SvcWrap_SleepThread64(Core::System& system, std::span<uint64_t, 8> args) { int64_t ns{}; - ns = Convert<int64_t>(GetReg64(system, 0)); + ns = Convert<int64_t>(GetArg64(args, 0)); SleepThread64(system, ns); } -static void SvcWrap_GetThreadPriority64(Core::System& system) { +static void SvcWrap_GetThreadPriority64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_priority{}; Handle thread_handle{}; - thread_handle = Convert<Handle>(GetReg64(system, 1)); + thread_handle = Convert<Handle>(GetArg64(args, 1)); ret = GetThreadPriority64(system, std::addressof(out_priority), thread_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_priority)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_priority)); } -static void SvcWrap_SetThreadPriority64(Core::System& system) { +static void SvcWrap_SetThreadPriority64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; int32_t priority{}; - thread_handle = Convert<Handle>(GetReg64(system, 0)); - priority = Convert<int32_t>(GetReg64(system, 1)); + thread_handle = Convert<Handle>(GetArg64(args, 0)); + priority = Convert<int32_t>(GetArg64(args, 1)); ret = SetThreadPriority64(system, thread_handle, priority); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_GetThreadCoreMask64(Core::System& system) { +static void SvcWrap_GetThreadCoreMask64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_core_id{}; uint64_t out_affinity_mask{}; Handle thread_handle{}; - thread_handle = Convert<Handle>(GetReg64(system, 2)); + thread_handle = Convert<Handle>(GetArg64(args, 2)); ret = GetThreadCoreMask64(system, std::addressof(out_core_id), std::addressof(out_affinity_mask), thread_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_core_id)); - SetReg64(system, 2, Convert<uint64_t>(out_affinity_mask)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_core_id)); + SetArg64(args, 2, Convert<uint64_t>(out_affinity_mask)); } -static void SvcWrap_SetThreadCoreMask64(Core::System& system) { +static void SvcWrap_SetThreadCoreMask64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; int32_t core_id{}; uint64_t affinity_mask{}; - thread_handle = Convert<Handle>(GetReg64(system, 0)); - core_id = Convert<int32_t>(GetReg64(system, 1)); - affinity_mask = Convert<uint64_t>(GetReg64(system, 2)); + thread_handle = Convert<Handle>(GetArg64(args, 0)); + core_id = Convert<int32_t>(GetArg64(args, 1)); + affinity_mask = Convert<uint64_t>(GetArg64(args, 2)); ret = SetThreadCoreMask64(system, thread_handle, core_id, affinity_mask); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_GetCurrentProcessorNumber64(Core::System& system) { +static void SvcWrap_GetCurrentProcessorNumber64(Core::System& system, std::span<uint64_t, 8> args) { int32_t ret{}; ret = GetCurrentProcessorNumber64(system); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SignalEvent64(Core::System& system) { +static void SvcWrap_SignalEvent64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle event_handle{}; - event_handle = Convert<Handle>(GetReg64(system, 0)); + event_handle = Convert<Handle>(GetArg64(args, 0)); ret = SignalEvent64(system, event_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_ClearEvent64(Core::System& system) { +static void SvcWrap_ClearEvent64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle event_handle{}; - event_handle = Convert<Handle>(GetReg64(system, 0)); + event_handle = Convert<Handle>(GetArg64(args, 0)); ret = ClearEvent64(system, event_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_MapSharedMemory64(Core::System& system) { +static void SvcWrap_MapSharedMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle shmem_handle{}; @@ -2331,33 +2331,33 @@ static void SvcWrap_MapSharedMemory64(Core::System& system) { uint64_t size{}; MemoryPermission map_perm{}; - shmem_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); - map_perm = Convert<MemoryPermission>(GetReg64(system, 3)); + shmem_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); + map_perm = Convert<MemoryPermission>(GetArg64(args, 3)); ret = MapSharedMemory64(system, shmem_handle, address, size, map_perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapSharedMemory64(Core::System& system) { +static void SvcWrap_UnmapSharedMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle shmem_handle{}; uint64_t address{}; uint64_t size{}; - shmem_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + shmem_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = UnmapSharedMemory64(system, shmem_handle, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_CreateTransferMemory64(Core::System& system) { +static void SvcWrap_CreateTransferMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -2365,41 +2365,41 @@ static void SvcWrap_CreateTransferMemory64(Core::System& system) { uint64_t size{}; MemoryPermission map_perm{}; - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); - map_perm = Convert<MemoryPermission>(GetReg64(system, 3)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); + map_perm = Convert<MemoryPermission>(GetArg64(args, 3)); ret = CreateTransferMemory64(system, std::addressof(out_handle), address, size, map_perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_CloseHandle64(Core::System& system) { +static void SvcWrap_CloseHandle64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle handle{}; - handle = Convert<Handle>(GetReg64(system, 0)); + handle = Convert<Handle>(GetArg64(args, 0)); ret = CloseHandle64(system, handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_ResetSignal64(Core::System& system) { +static void SvcWrap_ResetSignal64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle handle{}; - handle = Convert<Handle>(GetReg64(system, 0)); + handle = Convert<Handle>(GetArg64(args, 0)); ret = ResetSignal64(system, handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_WaitSynchronization64(Core::System& system) { +static void SvcWrap_WaitSynchronization64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_index{}; @@ -2407,57 +2407,57 @@ static void SvcWrap_WaitSynchronization64(Core::System& system) { int32_t num_handles{}; int64_t timeout_ns{}; - handles = Convert<uint64_t>(GetReg64(system, 1)); - num_handles = Convert<int32_t>(GetReg64(system, 2)); - timeout_ns = Convert<int64_t>(GetReg64(system, 3)); + handles = Convert<uint64_t>(GetArg64(args, 1)); + num_handles = Convert<int32_t>(GetArg64(args, 2)); + timeout_ns = Convert<int64_t>(GetArg64(args, 3)); ret = WaitSynchronization64(system, std::addressof(out_index), handles, num_handles, timeout_ns); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_index)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_index)); } -static void SvcWrap_CancelSynchronization64(Core::System& system) { +static void SvcWrap_CancelSynchronization64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle handle{}; - handle = Convert<Handle>(GetReg64(system, 0)); + handle = Convert<Handle>(GetArg64(args, 0)); ret = CancelSynchronization64(system, handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_ArbitrateLock64(Core::System& system) { +static void SvcWrap_ArbitrateLock64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; uint64_t address{}; uint32_t tag{}; - thread_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - tag = Convert<uint32_t>(GetReg64(system, 2)); + thread_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + tag = Convert<uint32_t>(GetArg64(args, 2)); ret = ArbitrateLock64(system, thread_handle, address, tag); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_ArbitrateUnlock64(Core::System& system) { +static void SvcWrap_ArbitrateUnlock64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; - address = Convert<uint64_t>(GetReg64(system, 0)); + address = Convert<uint64_t>(GetArg64(args, 0)); ret = ArbitrateUnlock64(system, address); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_WaitProcessWideKeyAtomic64(Core::System& system) { +static void SvcWrap_WaitProcessWideKeyAtomic64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; @@ -2465,77 +2465,77 @@ static void SvcWrap_WaitProcessWideKeyAtomic64(Core::System& system) { uint32_t tag{}; int64_t timeout_ns{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - cv_key = Convert<uint64_t>(GetReg64(system, 1)); - tag = Convert<uint32_t>(GetReg64(system, 2)); - timeout_ns = Convert<int64_t>(GetReg64(system, 3)); + address = Convert<uint64_t>(GetArg64(args, 0)); + cv_key = Convert<uint64_t>(GetArg64(args, 1)); + tag = Convert<uint32_t>(GetArg64(args, 2)); + timeout_ns = Convert<int64_t>(GetArg64(args, 3)); ret = WaitProcessWideKeyAtomic64(system, address, cv_key, tag, timeout_ns); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SignalProcessWideKey64(Core::System& system) { +static void SvcWrap_SignalProcessWideKey64(Core::System& system, std::span<uint64_t, 8> args) { uint64_t cv_key{}; int32_t count{}; - cv_key = Convert<uint64_t>(GetReg64(system, 0)); - count = Convert<int32_t>(GetReg64(system, 1)); + cv_key = Convert<uint64_t>(GetArg64(args, 0)); + count = Convert<int32_t>(GetArg64(args, 1)); SignalProcessWideKey64(system, cv_key, count); } -static void SvcWrap_GetSystemTick64(Core::System& system) { +static void SvcWrap_GetSystemTick64(Core::System& system, std::span<uint64_t, 8> args) { int64_t ret{}; ret = GetSystemTick64(system); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_ConnectToNamedPort64(Core::System& system) { +static void SvcWrap_ConnectToNamedPort64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; uint64_t name{}; - name = Convert<uint64_t>(GetReg64(system, 1)); + name = Convert<uint64_t>(GetArg64(args, 1)); ret = ConnectToNamedPort64(system, std::addressof(out_handle), name); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_SendSyncRequest64(Core::System& system) { +static void SvcWrap_SendSyncRequest64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle session_handle{}; - session_handle = Convert<Handle>(GetReg64(system, 0)); + session_handle = Convert<Handle>(GetArg64(args, 0)); ret = SendSyncRequest64(system, session_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SendSyncRequestWithUserBuffer64(Core::System& system) { +static void SvcWrap_SendSyncRequestWithUserBuffer64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t message_buffer{}; uint64_t message_buffer_size{}; Handle session_handle{}; - message_buffer = Convert<uint64_t>(GetReg64(system, 0)); - message_buffer_size = Convert<uint64_t>(GetReg64(system, 1)); - session_handle = Convert<Handle>(GetReg64(system, 2)); + message_buffer = Convert<uint64_t>(GetArg64(args, 0)); + message_buffer_size = Convert<uint64_t>(GetArg64(args, 1)); + session_handle = Convert<Handle>(GetArg64(args, 2)); ret = SendSyncRequestWithUserBuffer64(system, message_buffer, message_buffer_size, session_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SendAsyncRequestWithUserBuffer64(Core::System& system) { +static void SvcWrap_SendAsyncRequestWithUserBuffer64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_event_handle{}; @@ -2543,79 +2543,79 @@ static void SvcWrap_SendAsyncRequestWithUserBuffer64(Core::System& system) { uint64_t message_buffer_size{}; Handle session_handle{}; - message_buffer = Convert<uint64_t>(GetReg64(system, 1)); - message_buffer_size = Convert<uint64_t>(GetReg64(system, 2)); - session_handle = Convert<Handle>(GetReg64(system, 3)); + message_buffer = Convert<uint64_t>(GetArg64(args, 1)); + message_buffer_size = Convert<uint64_t>(GetArg64(args, 2)); + session_handle = Convert<Handle>(GetArg64(args, 3)); ret = SendAsyncRequestWithUserBuffer64(system, std::addressof(out_event_handle), message_buffer, message_buffer_size, session_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_event_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_event_handle)); } -static void SvcWrap_GetProcessId64(Core::System& system) { +static void SvcWrap_GetProcessId64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_process_id{}; Handle process_handle{}; - process_handle = Convert<Handle>(GetReg64(system, 1)); + process_handle = Convert<Handle>(GetArg64(args, 1)); ret = GetProcessId64(system, std::addressof(out_process_id), process_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_process_id)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_process_id)); } -static void SvcWrap_GetThreadId64(Core::System& system) { +static void SvcWrap_GetThreadId64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_thread_id{}; Handle thread_handle{}; - thread_handle = Convert<Handle>(GetReg64(system, 1)); + thread_handle = Convert<Handle>(GetArg64(args, 1)); ret = GetThreadId64(system, std::addressof(out_thread_id), thread_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_thread_id)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_thread_id)); } -static void SvcWrap_Break64(Core::System& system) { +static void SvcWrap_Break64(Core::System& system, std::span<uint64_t, 8> args) { BreakReason break_reason{}; uint64_t arg{}; uint64_t size{}; - break_reason = Convert<BreakReason>(GetReg64(system, 0)); - arg = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + break_reason = Convert<BreakReason>(GetArg64(args, 0)); + arg = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); Break64(system, break_reason, arg, size); } -static void SvcWrap_OutputDebugString64(Core::System& system) { +static void SvcWrap_OutputDebugString64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t debug_str{}; uint64_t len{}; - debug_str = Convert<uint64_t>(GetReg64(system, 0)); - len = Convert<uint64_t>(GetReg64(system, 1)); + debug_str = Convert<uint64_t>(GetArg64(args, 0)); + len = Convert<uint64_t>(GetArg64(args, 1)); ret = OutputDebugString64(system, debug_str, len); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_ReturnFromException64(Core::System& system) { +static void SvcWrap_ReturnFromException64(Core::System& system, std::span<uint64_t, 8> args) { Result result{}; - result = Convert<Result>(GetReg64(system, 0)); + result = Convert<Result>(GetArg64(args, 0)); ReturnFromException64(system, result); } -static void SvcWrap_GetInfo64(Core::System& system) { +static void SvcWrap_GetInfo64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out{}; @@ -2623,63 +2623,63 @@ static void SvcWrap_GetInfo64(Core::System& system) { Handle handle{}; uint64_t info_subtype{}; - info_type = Convert<InfoType>(GetReg64(system, 1)); - handle = Convert<Handle>(GetReg64(system, 2)); - info_subtype = Convert<uint64_t>(GetReg64(system, 3)); + info_type = Convert<InfoType>(GetArg64(args, 1)); + handle = Convert<Handle>(GetArg64(args, 2)); + info_subtype = Convert<uint64_t>(GetArg64(args, 3)); ret = GetInfo64(system, std::addressof(out), info_type, handle, info_subtype); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out)); } -static void SvcWrap_FlushEntireDataCache64(Core::System& system) { +static void SvcWrap_FlushEntireDataCache64(Core::System& system, std::span<uint64_t, 8> args) { FlushEntireDataCache64(system); } -static void SvcWrap_FlushDataCache64(Core::System& system) { +static void SvcWrap_FlushDataCache64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; uint64_t size{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); ret = FlushDataCache64(system, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_MapPhysicalMemory64(Core::System& system) { +static void SvcWrap_MapPhysicalMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; uint64_t size{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); ret = MapPhysicalMemory64(system, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapPhysicalMemory64(Core::System& system) { +static void SvcWrap_UnmapPhysicalMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; uint64_t size{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); ret = UnmapPhysicalMemory64(system, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_GetDebugFutureThreadInfo64(Core::System& system) { +static void SvcWrap_GetDebugFutureThreadInfo64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; lp64::LastThreadContext out_context{}; @@ -2687,21 +2687,21 @@ static void SvcWrap_GetDebugFutureThreadInfo64(Core::System& system) { Handle debug_handle{}; int64_t ns{}; - debug_handle = Convert<Handle>(GetReg64(system, 2)); - ns = Convert<int64_t>(GetReg64(system, 3)); + debug_handle = Convert<Handle>(GetArg64(args, 2)); + ns = Convert<int64_t>(GetArg64(args, 3)); ret = GetDebugFutureThreadInfo64(system, std::addressof(out_context), std::addressof(out_thread_id), debug_handle, ns); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context); - SetReg64(system, 1, out_context_scatter[0]); - SetReg64(system, 2, out_context_scatter[1]); - SetReg64(system, 3, out_context_scatter[2]); - SetReg64(system, 4, out_context_scatter[3]); - SetReg64(system, 5, Convert<uint64_t>(out_thread_id)); + SetArg64(args, 1, out_context_scatter[0]); + SetArg64(args, 2, out_context_scatter[1]); + SetArg64(args, 3, out_context_scatter[2]); + SetArg64(args, 4, out_context_scatter[3]); + SetArg64(args, 5, Convert<uint64_t>(out_thread_id)); } -static void SvcWrap_GetLastThreadInfo64(Core::System& system) { +static void SvcWrap_GetLastThreadInfo64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; lp64::LastThreadContext out_context{}; @@ -2710,77 +2710,77 @@ static void SvcWrap_GetLastThreadInfo64(Core::System& system) { ret = GetLastThreadInfo64(system, std::addressof(out_context), std::addressof(out_tls_address), std::addressof(out_flags)); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); auto out_context_scatter = Convert<std::array<uint64_t, 4>>(out_context); - SetReg64(system, 1, out_context_scatter[0]); - SetReg64(system, 2, out_context_scatter[1]); - SetReg64(system, 3, out_context_scatter[2]); - SetReg64(system, 4, out_context_scatter[3]); - SetReg64(system, 5, Convert<uint64_t>(out_tls_address)); - SetReg64(system, 6, Convert<uint64_t>(out_flags)); + SetArg64(args, 1, out_context_scatter[0]); + SetArg64(args, 2, out_context_scatter[1]); + SetArg64(args, 3, out_context_scatter[2]); + SetArg64(args, 4, out_context_scatter[3]); + SetArg64(args, 5, Convert<uint64_t>(out_tls_address)); + SetArg64(args, 6, Convert<uint64_t>(out_flags)); } -static void SvcWrap_GetResourceLimitLimitValue64(Core::System& system) { +static void SvcWrap_GetResourceLimitLimitValue64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int64_t out_limit_value{}; Handle resource_limit_handle{}; LimitableResource which{}; - resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); - which = Convert<LimitableResource>(GetReg64(system, 2)); + resource_limit_handle = Convert<Handle>(GetArg64(args, 1)); + which = Convert<LimitableResource>(GetArg64(args, 2)); ret = GetResourceLimitLimitValue64(system, std::addressof(out_limit_value), resource_limit_handle, which); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_limit_value)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_limit_value)); } -static void SvcWrap_GetResourceLimitCurrentValue64(Core::System& system) { +static void SvcWrap_GetResourceLimitCurrentValue64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int64_t out_current_value{}; Handle resource_limit_handle{}; LimitableResource which{}; - resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); - which = Convert<LimitableResource>(GetReg64(system, 2)); + resource_limit_handle = Convert<Handle>(GetArg64(args, 1)); + which = Convert<LimitableResource>(GetArg64(args, 2)); ret = GetResourceLimitCurrentValue64(system, std::addressof(out_current_value), resource_limit_handle, which); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_current_value)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_current_value)); } -static void SvcWrap_SetThreadActivity64(Core::System& system) { +static void SvcWrap_SetThreadActivity64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle thread_handle{}; ThreadActivity thread_activity{}; - thread_handle = Convert<Handle>(GetReg64(system, 0)); - thread_activity = Convert<ThreadActivity>(GetReg64(system, 1)); + thread_handle = Convert<Handle>(GetArg64(args, 0)); + thread_activity = Convert<ThreadActivity>(GetArg64(args, 1)); ret = SetThreadActivity64(system, thread_handle, thread_activity); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_GetThreadContext364(Core::System& system) { +static void SvcWrap_GetThreadContext364(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_context{}; Handle thread_handle{}; - out_context = Convert<uint64_t>(GetReg64(system, 0)); - thread_handle = Convert<Handle>(GetReg64(system, 1)); + out_context = Convert<uint64_t>(GetArg64(args, 0)); + thread_handle = Convert<Handle>(GetArg64(args, 1)); ret = GetThreadContext364(system, out_context, thread_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_WaitForAddress64(Core::System& system) { +static void SvcWrap_WaitForAddress64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; @@ -2788,17 +2788,17 @@ static void SvcWrap_WaitForAddress64(Core::System& system) { int32_t value{}; int64_t timeout_ns{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - arb_type = Convert<ArbitrationType>(GetReg64(system, 1)); - value = Convert<int32_t>(GetReg64(system, 2)); - timeout_ns = Convert<int64_t>(GetReg64(system, 3)); + address = Convert<uint64_t>(GetArg64(args, 0)); + arb_type = Convert<ArbitrationType>(GetArg64(args, 1)); + value = Convert<int32_t>(GetArg64(args, 2)); + timeout_ns = Convert<int64_t>(GetArg64(args, 3)); ret = WaitForAddress64(system, address, arb_type, value, timeout_ns); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SignalToAddress64(Core::System& system) { +static void SvcWrap_SignalToAddress64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; @@ -2806,51 +2806,51 @@ static void SvcWrap_SignalToAddress64(Core::System& system) { int32_t value{}; int32_t count{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - signal_type = Convert<SignalType>(GetReg64(system, 1)); - value = Convert<int32_t>(GetReg64(system, 2)); - count = Convert<int32_t>(GetReg64(system, 3)); + address = Convert<uint64_t>(GetArg64(args, 0)); + signal_type = Convert<SignalType>(GetArg64(args, 1)); + value = Convert<int32_t>(GetArg64(args, 2)); + count = Convert<int32_t>(GetArg64(args, 3)); ret = SignalToAddress64(system, address, signal_type, value, count); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SynchronizePreemptionState64(Core::System& system) { +static void SvcWrap_SynchronizePreemptionState64(Core::System& system, std::span<uint64_t, 8> args) { SynchronizePreemptionState64(system); } -static void SvcWrap_GetResourceLimitPeakValue64(Core::System& system) { +static void SvcWrap_GetResourceLimitPeakValue64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int64_t out_peak_value{}; Handle resource_limit_handle{}; LimitableResource which{}; - resource_limit_handle = Convert<Handle>(GetReg64(system, 1)); - which = Convert<LimitableResource>(GetReg64(system, 2)); + resource_limit_handle = Convert<Handle>(GetArg64(args, 1)); + which = Convert<LimitableResource>(GetArg64(args, 2)); ret = GetResourceLimitPeakValue64(system, std::addressof(out_peak_value), resource_limit_handle, which); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_peak_value)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_peak_value)); } -static void SvcWrap_CreateIoPool64(Core::System& system) { +static void SvcWrap_CreateIoPool64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; IoPoolType which{}; - which = Convert<IoPoolType>(GetReg64(system, 1)); + which = Convert<IoPoolType>(GetArg64(args, 1)); ret = CreateIoPool64(system, std::addressof(out_handle), which); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_CreateIoRegion64(Core::System& system) { +static void SvcWrap_CreateIoRegion64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -2860,41 +2860,41 @@ static void SvcWrap_CreateIoRegion64(Core::System& system) { MemoryMapping mapping{}; MemoryPermission perm{}; - io_pool = Convert<Handle>(GetReg64(system, 1)); - physical_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); - mapping = Convert<MemoryMapping>(GetReg64(system, 4)); - perm = Convert<MemoryPermission>(GetReg64(system, 5)); + io_pool = Convert<Handle>(GetArg64(args, 1)); + physical_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); + mapping = Convert<MemoryMapping>(GetArg64(args, 4)); + perm = Convert<MemoryPermission>(GetArg64(args, 5)); ret = CreateIoRegion64(system, std::addressof(out_handle), io_pool, physical_address, size, mapping, perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_KernelDebug64(Core::System& system) { +static void SvcWrap_KernelDebug64(Core::System& system, std::span<uint64_t, 8> args) { KernelDebugType kern_debug_type{}; uint64_t arg0{}; uint64_t arg1{}; uint64_t arg2{}; - kern_debug_type = Convert<KernelDebugType>(GetReg64(system, 0)); - arg0 = Convert<uint64_t>(GetReg64(system, 1)); - arg1 = Convert<uint64_t>(GetReg64(system, 2)); - arg2 = Convert<uint64_t>(GetReg64(system, 3)); + kern_debug_type = Convert<KernelDebugType>(GetArg64(args, 0)); + arg0 = Convert<uint64_t>(GetArg64(args, 1)); + arg1 = Convert<uint64_t>(GetArg64(args, 2)); + arg2 = Convert<uint64_t>(GetArg64(args, 3)); KernelDebug64(system, kern_debug_type, arg0, arg1, arg2); } -static void SvcWrap_ChangeKernelTraceState64(Core::System& system) { +static void SvcWrap_ChangeKernelTraceState64(Core::System& system, std::span<uint64_t, 8> args) { KernelTraceState kern_trace_state{}; - kern_trace_state = Convert<KernelTraceState>(GetReg64(system, 0)); + kern_trace_state = Convert<KernelTraceState>(GetArg64(args, 0)); ChangeKernelTraceState64(system, kern_trace_state); } -static void SvcWrap_CreateSession64(Core::System& system) { +static void SvcWrap_CreateSession64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_server_session_handle{}; @@ -2902,31 +2902,31 @@ static void SvcWrap_CreateSession64(Core::System& system) { bool is_light{}; uint64_t name{}; - is_light = Convert<bool>(GetReg64(system, 2)); - name = Convert<uint64_t>(GetReg64(system, 3)); + is_light = Convert<bool>(GetArg64(args, 2)); + name = Convert<uint64_t>(GetArg64(args, 3)); ret = CreateSession64(system, std::addressof(out_server_session_handle), std::addressof(out_client_session_handle), is_light, name); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_server_session_handle)); - SetReg64(system, 2, Convert<uint64_t>(out_client_session_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_server_session_handle)); + SetArg64(args, 2, Convert<uint64_t>(out_client_session_handle)); } -static void SvcWrap_AcceptSession64(Core::System& system) { +static void SvcWrap_AcceptSession64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; Handle port{}; - port = Convert<Handle>(GetReg64(system, 1)); + port = Convert<Handle>(GetArg64(args, 1)); ret = AcceptSession64(system, std::addressof(out_handle), port); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_ReplyAndReceive64(Core::System& system) { +static void SvcWrap_ReplyAndReceive64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_index{}; @@ -2935,18 +2935,18 @@ static void SvcWrap_ReplyAndReceive64(Core::System& system) { Handle reply_target{}; int64_t timeout_ns{}; - handles = Convert<uint64_t>(GetReg64(system, 1)); - num_handles = Convert<int32_t>(GetReg64(system, 2)); - reply_target = Convert<Handle>(GetReg64(system, 3)); - timeout_ns = Convert<int64_t>(GetReg64(system, 4)); + handles = Convert<uint64_t>(GetArg64(args, 1)); + num_handles = Convert<int32_t>(GetArg64(args, 2)); + reply_target = Convert<Handle>(GetArg64(args, 3)); + timeout_ns = Convert<int64_t>(GetArg64(args, 4)); ret = ReplyAndReceive64(system, std::addressof(out_index), handles, num_handles, reply_target, timeout_ns); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_index)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_index)); } -static void SvcWrap_ReplyAndReceiveWithUserBuffer64(Core::System& system) { +static void SvcWrap_ReplyAndReceiveWithUserBuffer64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_index{}; @@ -2957,20 +2957,20 @@ static void SvcWrap_ReplyAndReceiveWithUserBuffer64(Core::System& system) { Handle reply_target{}; int64_t timeout_ns{}; - message_buffer = Convert<uint64_t>(GetReg64(system, 1)); - message_buffer_size = Convert<uint64_t>(GetReg64(system, 2)); - handles = Convert<uint64_t>(GetReg64(system, 3)); - num_handles = Convert<int32_t>(GetReg64(system, 4)); - reply_target = Convert<Handle>(GetReg64(system, 5)); - timeout_ns = Convert<int64_t>(GetReg64(system, 6)); + message_buffer = Convert<uint64_t>(GetArg64(args, 1)); + message_buffer_size = Convert<uint64_t>(GetArg64(args, 2)); + handles = Convert<uint64_t>(GetArg64(args, 3)); + num_handles = Convert<int32_t>(GetArg64(args, 4)); + reply_target = Convert<Handle>(GetArg64(args, 5)); + timeout_ns = Convert<int64_t>(GetArg64(args, 6)); ret = ReplyAndReceiveWithUserBuffer64(system, std::addressof(out_index), message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_index)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_index)); } -static void SvcWrap_CreateEvent64(Core::System& system) { +static void SvcWrap_CreateEvent64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_write_handle{}; @@ -2978,12 +2978,12 @@ static void SvcWrap_CreateEvent64(Core::System& system) { ret = CreateEvent64(system, std::addressof(out_write_handle), std::addressof(out_read_handle)); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_write_handle)); - SetReg64(system, 2, Convert<uint64_t>(out_read_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_write_handle)); + SetArg64(args, 2, Convert<uint64_t>(out_read_handle)); } -static void SvcWrap_MapIoRegion64(Core::System& system) { +static void SvcWrap_MapIoRegion64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle io_region{}; @@ -2991,89 +2991,89 @@ static void SvcWrap_MapIoRegion64(Core::System& system) { uint64_t size{}; MemoryPermission perm{}; - io_region = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); - perm = Convert<MemoryPermission>(GetReg64(system, 3)); + io_region = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); + perm = Convert<MemoryPermission>(GetArg64(args, 3)); ret = MapIoRegion64(system, io_region, address, size, perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapIoRegion64(Core::System& system) { +static void SvcWrap_UnmapIoRegion64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle io_region{}; uint64_t address{}; uint64_t size{}; - io_region = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + io_region = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = UnmapIoRegion64(system, io_region, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_MapPhysicalMemoryUnsafe64(Core::System& system) { +static void SvcWrap_MapPhysicalMemoryUnsafe64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; uint64_t size{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); ret = MapPhysicalMemoryUnsafe64(system, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapPhysicalMemoryUnsafe64(Core::System& system) { +static void SvcWrap_UnmapPhysicalMemoryUnsafe64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; uint64_t size{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); ret = UnmapPhysicalMemoryUnsafe64(system, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SetUnsafeLimit64(Core::System& system) { +static void SvcWrap_SetUnsafeLimit64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t limit{}; - limit = Convert<uint64_t>(GetReg64(system, 0)); + limit = Convert<uint64_t>(GetArg64(args, 0)); ret = SetUnsafeLimit64(system, limit); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_CreateCodeMemory64(Core::System& system) { +static void SvcWrap_CreateCodeMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; uint64_t address{}; uint64_t size{}; - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = CreateCodeMemory64(system, std::addressof(out_handle), address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_ControlCodeMemory64(Core::System& system) { +static void SvcWrap_ControlCodeMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle code_memory_handle{}; @@ -3082,22 +3082,22 @@ static void SvcWrap_ControlCodeMemory64(Core::System& system) { uint64_t size{}; MemoryPermission perm{}; - code_memory_handle = Convert<Handle>(GetReg64(system, 0)); - operation = Convert<CodeMemoryOperation>(GetReg64(system, 1)); - address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); - perm = Convert<MemoryPermission>(GetReg64(system, 4)); + code_memory_handle = Convert<Handle>(GetArg64(args, 0)); + operation = Convert<CodeMemoryOperation>(GetArg64(args, 1)); + address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); + perm = Convert<MemoryPermission>(GetArg64(args, 4)); ret = ControlCodeMemory64(system, code_memory_handle, operation, address, size, perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SleepSystem64(Core::System& system) { +static void SvcWrap_SleepSystem64(Core::System& system, std::span<uint64_t, 8> args) { SleepSystem64(system); } -static void SvcWrap_ReadWriteRegister64(Core::System& system) { +static void SvcWrap_ReadWriteRegister64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint32_t out_value{}; @@ -3105,31 +3105,31 @@ static void SvcWrap_ReadWriteRegister64(Core::System& system) { uint32_t mask{}; uint32_t value{}; - address = Convert<uint64_t>(GetReg64(system, 1)); - mask = Convert<uint32_t>(GetReg64(system, 2)); - value = Convert<uint32_t>(GetReg64(system, 3)); + address = Convert<uint64_t>(GetArg64(args, 1)); + mask = Convert<uint32_t>(GetArg64(args, 2)); + value = Convert<uint32_t>(GetArg64(args, 3)); ret = ReadWriteRegister64(system, std::addressof(out_value), address, mask, value); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_value)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_value)); } -static void SvcWrap_SetProcessActivity64(Core::System& system) { +static void SvcWrap_SetProcessActivity64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; ProcessActivity process_activity{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); - process_activity = Convert<ProcessActivity>(GetReg64(system, 1)); + process_handle = Convert<Handle>(GetArg64(args, 0)); + process_activity = Convert<ProcessActivity>(GetArg64(args, 1)); ret = SetProcessActivity64(system, process_handle, process_activity); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_CreateSharedMemory64(Core::System& system) { +static void SvcWrap_CreateSharedMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -3137,17 +3137,17 @@ static void SvcWrap_CreateSharedMemory64(Core::System& system) { MemoryPermission owner_perm{}; MemoryPermission remote_perm{}; - size = Convert<uint64_t>(GetReg64(system, 1)); - owner_perm = Convert<MemoryPermission>(GetReg64(system, 2)); - remote_perm = Convert<MemoryPermission>(GetReg64(system, 3)); + size = Convert<uint64_t>(GetArg64(args, 1)); + owner_perm = Convert<MemoryPermission>(GetArg64(args, 2)); + remote_perm = Convert<MemoryPermission>(GetArg64(args, 3)); ret = CreateSharedMemory64(system, std::addressof(out_handle), size, owner_perm, remote_perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_MapTransferMemory64(Core::System& system) { +static void SvcWrap_MapTransferMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle trmem_handle{}; @@ -3155,66 +3155,66 @@ static void SvcWrap_MapTransferMemory64(Core::System& system) { uint64_t size{}; MemoryPermission owner_perm{}; - trmem_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); - owner_perm = Convert<MemoryPermission>(GetReg64(system, 3)); + trmem_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); + owner_perm = Convert<MemoryPermission>(GetArg64(args, 3)); ret = MapTransferMemory64(system, trmem_handle, address, size, owner_perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapTransferMemory64(Core::System& system) { +static void SvcWrap_UnmapTransferMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle trmem_handle{}; uint64_t address{}; uint64_t size{}; - trmem_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + trmem_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = UnmapTransferMemory64(system, trmem_handle, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_CreateInterruptEvent64(Core::System& system) { +static void SvcWrap_CreateInterruptEvent64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_read_handle{}; int32_t interrupt_id{}; InterruptType interrupt_type{}; - interrupt_id = Convert<int32_t>(GetReg64(system, 1)); - interrupt_type = Convert<InterruptType>(GetReg64(system, 2)); + interrupt_id = Convert<int32_t>(GetArg64(args, 1)); + interrupt_type = Convert<InterruptType>(GetArg64(args, 2)); ret = CreateInterruptEvent64(system, std::addressof(out_read_handle), interrupt_id, interrupt_type); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_read_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_read_handle)); } -static void SvcWrap_QueryPhysicalAddress64(Core::System& system) { +static void SvcWrap_QueryPhysicalAddress64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; lp64::PhysicalMemoryInfo out_info{}; uint64_t address{}; - address = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetArg64(args, 1)); ret = QueryPhysicalAddress64(system, std::addressof(out_info), address); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); auto out_info_scatter = Convert<std::array<uint64_t, 3>>(out_info); - SetReg64(system, 1, out_info_scatter[0]); - SetReg64(system, 2, out_info_scatter[1]); - SetReg64(system, 3, out_info_scatter[2]); + SetArg64(args, 1, out_info_scatter[0]); + SetArg64(args, 2, out_info_scatter[1]); + SetArg64(args, 3, out_info_scatter[2]); } -static void SvcWrap_QueryIoMapping64(Core::System& system) { +static void SvcWrap_QueryIoMapping64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_address{}; @@ -3222,61 +3222,61 @@ static void SvcWrap_QueryIoMapping64(Core::System& system) { uint64_t physical_address{}; uint64_t size{}; - physical_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); + physical_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); ret = QueryIoMapping64(system, std::addressof(out_address), std::addressof(out_size), physical_address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_address)); - SetReg64(system, 2, Convert<uint64_t>(out_size)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_address)); + SetArg64(args, 2, Convert<uint64_t>(out_size)); } -static void SvcWrap_CreateDeviceAddressSpace64(Core::System& system) { +static void SvcWrap_CreateDeviceAddressSpace64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; uint64_t das_address{}; uint64_t das_size{}; - das_address = Convert<uint64_t>(GetReg64(system, 1)); - das_size = Convert<uint64_t>(GetReg64(system, 2)); + das_address = Convert<uint64_t>(GetArg64(args, 1)); + das_size = Convert<uint64_t>(GetArg64(args, 2)); ret = CreateDeviceAddressSpace64(system, std::addressof(out_handle), das_address, das_size); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_AttachDeviceAddressSpace64(Core::System& system) { +static void SvcWrap_AttachDeviceAddressSpace64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; DeviceName device_name{}; Handle das_handle{}; - device_name = Convert<DeviceName>(GetReg64(system, 0)); - das_handle = Convert<Handle>(GetReg64(system, 1)); + device_name = Convert<DeviceName>(GetArg64(args, 0)); + das_handle = Convert<Handle>(GetArg64(args, 1)); ret = AttachDeviceAddressSpace64(system, device_name, das_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_DetachDeviceAddressSpace64(Core::System& system) { +static void SvcWrap_DetachDeviceAddressSpace64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; DeviceName device_name{}; Handle das_handle{}; - device_name = Convert<DeviceName>(GetReg64(system, 0)); - das_handle = Convert<Handle>(GetReg64(system, 1)); + device_name = Convert<DeviceName>(GetArg64(args, 0)); + das_handle = Convert<Handle>(GetArg64(args, 1)); ret = DetachDeviceAddressSpace64(system, device_name, das_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_MapDeviceAddressSpaceByForce64(Core::System& system) { +static void SvcWrap_MapDeviceAddressSpaceByForce64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle das_handle{}; @@ -3286,19 +3286,19 @@ static void SvcWrap_MapDeviceAddressSpaceByForce64(Core::System& system) { uint64_t device_address{}; uint32_t option{}; - das_handle = Convert<Handle>(GetReg64(system, 0)); - process_handle = Convert<Handle>(GetReg64(system, 1)); - process_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); - device_address = Convert<uint64_t>(GetReg64(system, 4)); - option = Convert<uint32_t>(GetReg64(system, 5)); + das_handle = Convert<Handle>(GetArg64(args, 0)); + process_handle = Convert<Handle>(GetArg64(args, 1)); + process_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); + device_address = Convert<uint64_t>(GetArg64(args, 4)); + option = Convert<uint32_t>(GetArg64(args, 5)); ret = MapDeviceAddressSpaceByForce64(system, das_handle, process_handle, process_address, size, device_address, option); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_MapDeviceAddressSpaceAligned64(Core::System& system) { +static void SvcWrap_MapDeviceAddressSpaceAligned64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle das_handle{}; @@ -3308,19 +3308,19 @@ static void SvcWrap_MapDeviceAddressSpaceAligned64(Core::System& system) { uint64_t device_address{}; uint32_t option{}; - das_handle = Convert<Handle>(GetReg64(system, 0)); - process_handle = Convert<Handle>(GetReg64(system, 1)); - process_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); - device_address = Convert<uint64_t>(GetReg64(system, 4)); - option = Convert<uint32_t>(GetReg64(system, 5)); + das_handle = Convert<Handle>(GetArg64(args, 0)); + process_handle = Convert<Handle>(GetArg64(args, 1)); + process_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); + device_address = Convert<uint64_t>(GetArg64(args, 4)); + option = Convert<uint32_t>(GetArg64(args, 5)); ret = MapDeviceAddressSpaceAligned64(system, das_handle, process_handle, process_address, size, device_address, option); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapDeviceAddressSpace64(Core::System& system) { +static void SvcWrap_UnmapDeviceAddressSpace64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle das_handle{}; @@ -3329,118 +3329,118 @@ static void SvcWrap_UnmapDeviceAddressSpace64(Core::System& system) { uint64_t size{}; uint64_t device_address{}; - das_handle = Convert<Handle>(GetReg64(system, 0)); - process_handle = Convert<Handle>(GetReg64(system, 1)); - process_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); - device_address = Convert<uint64_t>(GetReg64(system, 4)); + das_handle = Convert<Handle>(GetArg64(args, 0)); + process_handle = Convert<Handle>(GetArg64(args, 1)); + process_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); + device_address = Convert<uint64_t>(GetArg64(args, 4)); ret = UnmapDeviceAddressSpace64(system, das_handle, process_handle, process_address, size, device_address); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_InvalidateProcessDataCache64(Core::System& system) { +static void SvcWrap_InvalidateProcessDataCache64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; uint64_t address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + process_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = InvalidateProcessDataCache64(system, process_handle, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_StoreProcessDataCache64(Core::System& system) { +static void SvcWrap_StoreProcessDataCache64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; uint64_t address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + process_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = StoreProcessDataCache64(system, process_handle, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_FlushProcessDataCache64(Core::System& system) { +static void SvcWrap_FlushProcessDataCache64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; uint64_t address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); + process_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); ret = FlushProcessDataCache64(system, process_handle, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_DebugActiveProcess64(Core::System& system) { +static void SvcWrap_DebugActiveProcess64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; uint64_t process_id{}; - process_id = Convert<uint64_t>(GetReg64(system, 1)); + process_id = Convert<uint64_t>(GetArg64(args, 1)); ret = DebugActiveProcess64(system, std::addressof(out_handle), process_id); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_BreakDebugProcess64(Core::System& system) { +static void SvcWrap_BreakDebugProcess64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; - debug_handle = Convert<Handle>(GetReg64(system, 0)); + debug_handle = Convert<Handle>(GetArg64(args, 0)); ret = BreakDebugProcess64(system, debug_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_TerminateDebugProcess64(Core::System& system) { +static void SvcWrap_TerminateDebugProcess64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; - debug_handle = Convert<Handle>(GetReg64(system, 0)); + debug_handle = Convert<Handle>(GetArg64(args, 0)); ret = TerminateDebugProcess64(system, debug_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_GetDebugEvent64(Core::System& system) { +static void SvcWrap_GetDebugEvent64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_info{}; Handle debug_handle{}; - out_info = Convert<uint64_t>(GetReg64(system, 0)); - debug_handle = Convert<Handle>(GetReg64(system, 1)); + out_info = Convert<uint64_t>(GetArg64(args, 0)); + debug_handle = Convert<Handle>(GetArg64(args, 1)); ret = GetDebugEvent64(system, out_info, debug_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_ContinueDebugEvent64(Core::System& system) { +static void SvcWrap_ContinueDebugEvent64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; @@ -3448,33 +3448,33 @@ static void SvcWrap_ContinueDebugEvent64(Core::System& system) { uint64_t thread_ids{}; int32_t num_thread_ids{}; - debug_handle = Convert<Handle>(GetReg64(system, 0)); - flags = Convert<uint32_t>(GetReg64(system, 1)); - thread_ids = Convert<uint64_t>(GetReg64(system, 2)); - num_thread_ids = Convert<int32_t>(GetReg64(system, 3)); + debug_handle = Convert<Handle>(GetArg64(args, 0)); + flags = Convert<uint32_t>(GetArg64(args, 1)); + thread_ids = Convert<uint64_t>(GetArg64(args, 2)); + num_thread_ids = Convert<int32_t>(GetArg64(args, 3)); ret = ContinueDebugEvent64(system, debug_handle, flags, thread_ids, num_thread_ids); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_GetProcessList64(Core::System& system) { +static void SvcWrap_GetProcessList64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_num_processes{}; uint64_t out_process_ids{}; int32_t max_out_count{}; - out_process_ids = Convert<uint64_t>(GetReg64(system, 1)); - max_out_count = Convert<int32_t>(GetReg64(system, 2)); + out_process_ids = Convert<uint64_t>(GetArg64(args, 1)); + max_out_count = Convert<int32_t>(GetArg64(args, 2)); ret = GetProcessList64(system, std::addressof(out_num_processes), out_process_ids, max_out_count); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_num_processes)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_num_processes)); } -static void SvcWrap_GetThreadList64(Core::System& system) { +static void SvcWrap_GetThreadList64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int32_t out_num_threads{}; @@ -3482,17 +3482,17 @@ static void SvcWrap_GetThreadList64(Core::System& system) { int32_t max_out_count{}; Handle debug_handle{}; - out_thread_ids = Convert<uint64_t>(GetReg64(system, 1)); - max_out_count = Convert<int32_t>(GetReg64(system, 2)); - debug_handle = Convert<Handle>(GetReg64(system, 3)); + out_thread_ids = Convert<uint64_t>(GetArg64(args, 1)); + max_out_count = Convert<int32_t>(GetArg64(args, 2)); + debug_handle = Convert<Handle>(GetArg64(args, 3)); ret = GetThreadList64(system, std::addressof(out_num_threads), out_thread_ids, max_out_count, debug_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_num_threads)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_num_threads)); } -static void SvcWrap_GetDebugThreadContext64(Core::System& system) { +static void SvcWrap_GetDebugThreadContext64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_context{}; @@ -3500,17 +3500,17 @@ static void SvcWrap_GetDebugThreadContext64(Core::System& system) { uint64_t thread_id{}; uint32_t context_flags{}; - out_context = Convert<uint64_t>(GetReg64(system, 0)); - debug_handle = Convert<Handle>(GetReg64(system, 1)); - thread_id = Convert<uint64_t>(GetReg64(system, 2)); - context_flags = Convert<uint32_t>(GetReg64(system, 3)); + out_context = Convert<uint64_t>(GetArg64(args, 0)); + debug_handle = Convert<Handle>(GetArg64(args, 1)); + thread_id = Convert<uint64_t>(GetArg64(args, 2)); + context_flags = Convert<uint32_t>(GetArg64(args, 3)); ret = GetDebugThreadContext64(system, out_context, debug_handle, thread_id, context_flags); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SetDebugThreadContext64(Core::System& system) { +static void SvcWrap_SetDebugThreadContext64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; @@ -3518,17 +3518,17 @@ static void SvcWrap_SetDebugThreadContext64(Core::System& system) { uint64_t context{}; uint32_t context_flags{}; - debug_handle = Convert<Handle>(GetReg64(system, 0)); - thread_id = Convert<uint64_t>(GetReg64(system, 1)); - context = Convert<uint64_t>(GetReg64(system, 2)); - context_flags = Convert<uint32_t>(GetReg64(system, 3)); + debug_handle = Convert<Handle>(GetArg64(args, 0)); + thread_id = Convert<uint64_t>(GetArg64(args, 1)); + context = Convert<uint64_t>(GetArg64(args, 2)); + context_flags = Convert<uint32_t>(GetArg64(args, 3)); ret = SetDebugThreadContext64(system, debug_handle, thread_id, context, context_flags); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_QueryDebugProcessMemory64(Core::System& system) { +static void SvcWrap_QueryDebugProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; PageInfo out_page_info{}; @@ -3536,17 +3536,17 @@ static void SvcWrap_QueryDebugProcessMemory64(Core::System& system) { Handle process_handle{}; uint64_t address{}; - out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); - process_handle = Convert<Handle>(GetReg64(system, 2)); - address = Convert<uint64_t>(GetReg64(system, 3)); + out_memory_info = Convert<uint64_t>(GetArg64(args, 0)); + process_handle = Convert<Handle>(GetArg64(args, 2)); + address = Convert<uint64_t>(GetArg64(args, 3)); ret = QueryDebugProcessMemory64(system, out_memory_info, std::addressof(out_page_info), process_handle, address); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_page_info)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_page_info)); } -static void SvcWrap_ReadDebugProcessMemory64(Core::System& system) { +static void SvcWrap_ReadDebugProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t buffer{}; @@ -3554,17 +3554,17 @@ static void SvcWrap_ReadDebugProcessMemory64(Core::System& system) { uint64_t address{}; uint64_t size{}; - buffer = Convert<uint64_t>(GetReg64(system, 0)); - debug_handle = Convert<Handle>(GetReg64(system, 1)); - address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); + buffer = Convert<uint64_t>(GetArg64(args, 0)); + debug_handle = Convert<Handle>(GetArg64(args, 1)); + address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); ret = ReadDebugProcessMemory64(system, buffer, debug_handle, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_WriteDebugProcessMemory64(Core::System& system) { +static void SvcWrap_WriteDebugProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle debug_handle{}; @@ -3572,33 +3572,33 @@ static void SvcWrap_WriteDebugProcessMemory64(Core::System& system) { uint64_t address{}; uint64_t size{}; - debug_handle = Convert<Handle>(GetReg64(system, 0)); - buffer = Convert<uint64_t>(GetReg64(system, 1)); - address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); + debug_handle = Convert<Handle>(GetArg64(args, 0)); + buffer = Convert<uint64_t>(GetArg64(args, 1)); + address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); ret = WriteDebugProcessMemory64(system, debug_handle, buffer, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_SetHardwareBreakPoint64(Core::System& system) { +static void SvcWrap_SetHardwareBreakPoint64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; HardwareBreakPointRegisterName name{}; uint64_t flags{}; uint64_t value{}; - name = Convert<HardwareBreakPointRegisterName>(GetReg64(system, 0)); - flags = Convert<uint64_t>(GetReg64(system, 1)); - value = Convert<uint64_t>(GetReg64(system, 2)); + name = Convert<HardwareBreakPointRegisterName>(GetArg64(args, 0)); + flags = Convert<uint64_t>(GetArg64(args, 1)); + value = Convert<uint64_t>(GetArg64(args, 2)); ret = SetHardwareBreakPoint64(system, name, flags, value); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_GetDebugThreadParam64(Core::System& system) { +static void SvcWrap_GetDebugThreadParam64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out_64{}; @@ -3607,18 +3607,18 @@ static void SvcWrap_GetDebugThreadParam64(Core::System& system) { uint64_t thread_id{}; DebugThreadParam param{}; - debug_handle = Convert<Handle>(GetReg64(system, 2)); - thread_id = Convert<uint64_t>(GetReg64(system, 3)); - param = Convert<DebugThreadParam>(GetReg64(system, 4)); + debug_handle = Convert<Handle>(GetArg64(args, 2)); + thread_id = Convert<uint64_t>(GetArg64(args, 3)); + param = Convert<DebugThreadParam>(GetArg64(args, 4)); ret = GetDebugThreadParam64(system, std::addressof(out_64), std::addressof(out_32), debug_handle, thread_id, param); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_64)); - SetReg64(system, 2, Convert<uint64_t>(out_32)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_64)); + SetArg64(args, 2, Convert<uint64_t>(out_32)); } -static void SvcWrap_GetSystemInfo64(Core::System& system) { +static void SvcWrap_GetSystemInfo64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t out{}; @@ -3626,17 +3626,17 @@ static void SvcWrap_GetSystemInfo64(Core::System& system) { Handle handle{}; uint64_t info_subtype{}; - info_type = Convert<SystemInfoType>(GetReg64(system, 1)); - handle = Convert<Handle>(GetReg64(system, 2)); - info_subtype = Convert<uint64_t>(GetReg64(system, 3)); + info_type = Convert<SystemInfoType>(GetArg64(args, 1)); + handle = Convert<Handle>(GetArg64(args, 2)); + info_subtype = Convert<uint64_t>(GetArg64(args, 3)); ret = GetSystemInfo64(system, std::addressof(out), info_type, handle, info_subtype); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out)); } -static void SvcWrap_CreatePort64(Core::System& system) { +static void SvcWrap_CreatePort64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_server_handle{}; @@ -3645,48 +3645,48 @@ static void SvcWrap_CreatePort64(Core::System& system) { bool is_light{}; uint64_t name{}; - max_sessions = Convert<int32_t>(GetReg64(system, 2)); - is_light = Convert<bool>(GetReg64(system, 3)); - name = Convert<uint64_t>(GetReg64(system, 4)); + max_sessions = Convert<int32_t>(GetArg64(args, 2)); + is_light = Convert<bool>(GetArg64(args, 3)); + name = Convert<uint64_t>(GetArg64(args, 4)); ret = CreatePort64(system, std::addressof(out_server_handle), std::addressof(out_client_handle), max_sessions, is_light, name); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_server_handle)); - SetReg64(system, 2, Convert<uint64_t>(out_client_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_server_handle)); + SetArg64(args, 2, Convert<uint64_t>(out_client_handle)); } -static void SvcWrap_ManageNamedPort64(Core::System& system) { +static void SvcWrap_ManageNamedPort64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_server_handle{}; uint64_t name{}; int32_t max_sessions{}; - name = Convert<uint64_t>(GetReg64(system, 1)); - max_sessions = Convert<int32_t>(GetReg64(system, 2)); + name = Convert<uint64_t>(GetArg64(args, 1)); + max_sessions = Convert<int32_t>(GetArg64(args, 2)); ret = ManageNamedPort64(system, std::addressof(out_server_handle), name, max_sessions); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_server_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_server_handle)); } -static void SvcWrap_ConnectToPort64(Core::System& system) { +static void SvcWrap_ConnectToPort64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; Handle port{}; - port = Convert<Handle>(GetReg64(system, 1)); + port = Convert<Handle>(GetArg64(args, 1)); ret = ConnectToPort64(system, std::addressof(out_handle), port); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_SetProcessMemoryPermission64(Core::System& system) { +static void SvcWrap_SetProcessMemoryPermission64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; @@ -3694,17 +3694,17 @@ static void SvcWrap_SetProcessMemoryPermission64(Core::System& system) { uint64_t size{}; MemoryPermission perm{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); - address = Convert<uint64_t>(GetReg64(system, 1)); - size = Convert<uint64_t>(GetReg64(system, 2)); - perm = Convert<MemoryPermission>(GetReg64(system, 3)); + process_handle = Convert<Handle>(GetArg64(args, 0)); + address = Convert<uint64_t>(GetArg64(args, 1)); + size = Convert<uint64_t>(GetArg64(args, 2)); + perm = Convert<MemoryPermission>(GetArg64(args, 3)); ret = SetProcessMemoryPermission64(system, process_handle, address, size, perm); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_MapProcessMemory64(Core::System& system) { +static void SvcWrap_MapProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t dst_address{}; @@ -3712,17 +3712,17 @@ static void SvcWrap_MapProcessMemory64(Core::System& system) { uint64_t src_address{}; uint64_t size{}; - dst_address = Convert<uint64_t>(GetReg64(system, 0)); - process_handle = Convert<Handle>(GetReg64(system, 1)); - src_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); + dst_address = Convert<uint64_t>(GetArg64(args, 0)); + process_handle = Convert<Handle>(GetArg64(args, 1)); + src_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); ret = MapProcessMemory64(system, dst_address, process_handle, src_address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapProcessMemory64(Core::System& system) { +static void SvcWrap_UnmapProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t dst_address{}; @@ -3730,17 +3730,17 @@ static void SvcWrap_UnmapProcessMemory64(Core::System& system) { uint64_t src_address{}; uint64_t size{}; - dst_address = Convert<uint64_t>(GetReg64(system, 0)); - process_handle = Convert<Handle>(GetReg64(system, 1)); - src_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); + dst_address = Convert<uint64_t>(GetArg64(args, 0)); + process_handle = Convert<Handle>(GetArg64(args, 1)); + src_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); ret = UnmapProcessMemory64(system, dst_address, process_handle, src_address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_QueryProcessMemory64(Core::System& system) { +static void SvcWrap_QueryProcessMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; PageInfo out_page_info{}; @@ -3748,17 +3748,17 @@ static void SvcWrap_QueryProcessMemory64(Core::System& system) { Handle process_handle{}; uint64_t address{}; - out_memory_info = Convert<uint64_t>(GetReg64(system, 0)); - process_handle = Convert<Handle>(GetReg64(system, 2)); - address = Convert<uint64_t>(GetReg64(system, 3)); + out_memory_info = Convert<uint64_t>(GetArg64(args, 0)); + process_handle = Convert<Handle>(GetArg64(args, 2)); + address = Convert<uint64_t>(GetArg64(args, 3)); ret = QueryProcessMemory64(system, out_memory_info, std::addressof(out_page_info), process_handle, address); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_page_info)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_page_info)); } -static void SvcWrap_MapProcessCodeMemory64(Core::System& system) { +static void SvcWrap_MapProcessCodeMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; @@ -3766,17 +3766,17 @@ static void SvcWrap_MapProcessCodeMemory64(Core::System& system) { uint64_t src_address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); - dst_address = Convert<uint64_t>(GetReg64(system, 1)); - src_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); + process_handle = Convert<Handle>(GetArg64(args, 0)); + dst_address = Convert<uint64_t>(GetArg64(args, 1)); + src_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); ret = MapProcessCodeMemory64(system, process_handle, dst_address, src_address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapProcessCodeMemory64(Core::System& system) { +static void SvcWrap_UnmapProcessCodeMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; @@ -3784,17 +3784,17 @@ static void SvcWrap_UnmapProcessCodeMemory64(Core::System& system) { uint64_t src_address{}; uint64_t size{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); - dst_address = Convert<uint64_t>(GetReg64(system, 1)); - src_address = Convert<uint64_t>(GetReg64(system, 2)); - size = Convert<uint64_t>(GetReg64(system, 3)); + process_handle = Convert<Handle>(GetArg64(args, 0)); + dst_address = Convert<uint64_t>(GetArg64(args, 1)); + src_address = Convert<uint64_t>(GetArg64(args, 2)); + size = Convert<uint64_t>(GetArg64(args, 3)); ret = UnmapProcessCodeMemory64(system, process_handle, dst_address, src_address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_CreateProcess64(Core::System& system) { +static void SvcWrap_CreateProcess64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; @@ -3802,17 +3802,17 @@ static void SvcWrap_CreateProcess64(Core::System& system) { uint64_t caps{}; int32_t num_caps{}; - parameters = Convert<uint64_t>(GetReg64(system, 1)); - caps = Convert<uint64_t>(GetReg64(system, 2)); - num_caps = Convert<int32_t>(GetReg64(system, 3)); + parameters = Convert<uint64_t>(GetArg64(args, 1)); + caps = Convert<uint64_t>(GetArg64(args, 2)); + num_caps = Convert<int32_t>(GetArg64(args, 3)); ret = CreateProcess64(system, std::addressof(out_handle), parameters, caps, num_caps); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_StartProcess64(Core::System& system) { +static void SvcWrap_StartProcess64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; @@ -3820,601 +3820,601 @@ static void SvcWrap_StartProcess64(Core::System& system) { int32_t core_id{}; uint64_t main_thread_stack_size{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); - priority = Convert<int32_t>(GetReg64(system, 1)); - core_id = Convert<int32_t>(GetReg64(system, 2)); - main_thread_stack_size = Convert<uint64_t>(GetReg64(system, 3)); + process_handle = Convert<Handle>(GetArg64(args, 0)); + priority = Convert<int32_t>(GetArg64(args, 1)); + core_id = Convert<int32_t>(GetArg64(args, 2)); + main_thread_stack_size = Convert<uint64_t>(GetArg64(args, 3)); ret = StartProcess64(system, process_handle, priority, core_id, main_thread_stack_size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_TerminateProcess64(Core::System& system) { +static void SvcWrap_TerminateProcess64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle process_handle{}; - process_handle = Convert<Handle>(GetReg64(system, 0)); + process_handle = Convert<Handle>(GetArg64(args, 0)); ret = TerminateProcess64(system, process_handle); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_GetProcessInfo64(Core::System& system) { +static void SvcWrap_GetProcessInfo64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; int64_t out_info{}; Handle process_handle{}; ProcessInfoType info_type{}; - process_handle = Convert<Handle>(GetReg64(system, 1)); - info_type = Convert<ProcessInfoType>(GetReg64(system, 2)); + process_handle = Convert<Handle>(GetArg64(args, 1)); + info_type = Convert<ProcessInfoType>(GetArg64(args, 2)); ret = GetProcessInfo64(system, std::addressof(out_info), process_handle, info_type); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_info)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_info)); } -static void SvcWrap_CreateResourceLimit64(Core::System& system) { +static void SvcWrap_CreateResourceLimit64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle out_handle{}; ret = CreateResourceLimit64(system, std::addressof(out_handle)); - SetReg64(system, 0, Convert<uint64_t>(ret)); - SetReg64(system, 1, Convert<uint64_t>(out_handle)); + SetArg64(args, 0, Convert<uint64_t>(ret)); + SetArg64(args, 1, Convert<uint64_t>(out_handle)); } -static void SvcWrap_SetResourceLimitLimitValue64(Core::System& system) { +static void SvcWrap_SetResourceLimitLimitValue64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; Handle resource_limit_handle{}; LimitableResource which{}; int64_t limit_value{}; - resource_limit_handle = Convert<Handle>(GetReg64(system, 0)); - which = Convert<LimitableResource>(GetReg64(system, 1)); - limit_value = Convert<int64_t>(GetReg64(system, 2)); + resource_limit_handle = Convert<Handle>(GetArg64(args, 0)); + which = Convert<LimitableResource>(GetArg64(args, 1)); + limit_value = Convert<int64_t>(GetArg64(args, 2)); ret = SetResourceLimitLimitValue64(system, resource_limit_handle, which, limit_value); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_MapInsecureMemory64(Core::System& system) { +static void SvcWrap_MapInsecureMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; uint64_t size{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); ret = MapInsecureMemory64(system, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void SvcWrap_UnmapInsecureMemory64(Core::System& system) { +static void SvcWrap_UnmapInsecureMemory64(Core::System& system, std::span<uint64_t, 8> args) { Result ret{}; uint64_t address{}; uint64_t size{}; - address = Convert<uint64_t>(GetReg64(system, 0)); - size = Convert<uint64_t>(GetReg64(system, 1)); + address = Convert<uint64_t>(GetArg64(args, 0)); + size = Convert<uint64_t>(GetArg64(args, 1)); ret = UnmapInsecureMemory64(system, address, size); - SetReg64(system, 0, Convert<uint64_t>(ret)); + SetArg64(args, 0, Convert<uint64_t>(ret)); } -static void Call32(Core::System& system, u32 imm) { +static void Call32(Core::System& system, u32 imm, std::span<uint64_t, 8> args) { switch (static_cast<SvcId>(imm)) { case SvcId::SetHeapSize: - return SvcWrap_SetHeapSize64From32(system); + return SvcWrap_SetHeapSize64From32(system, args); case SvcId::SetMemoryPermission: - return SvcWrap_SetMemoryPermission64From32(system); + return SvcWrap_SetMemoryPermission64From32(system, args); case SvcId::SetMemoryAttribute: - return SvcWrap_SetMemoryAttribute64From32(system); + return SvcWrap_SetMemoryAttribute64From32(system, args); case SvcId::MapMemory: - return SvcWrap_MapMemory64From32(system); + return SvcWrap_MapMemory64From32(system, args); case SvcId::UnmapMemory: - return SvcWrap_UnmapMemory64From32(system); + return SvcWrap_UnmapMemory64From32(system, args); case SvcId::QueryMemory: - return SvcWrap_QueryMemory64From32(system); + return SvcWrap_QueryMemory64From32(system, args); case SvcId::ExitProcess: - return SvcWrap_ExitProcess64From32(system); + return SvcWrap_ExitProcess64From32(system, args); case SvcId::CreateThread: - return SvcWrap_CreateThread64From32(system); + return SvcWrap_CreateThread64From32(system, args); case SvcId::StartThread: - return SvcWrap_StartThread64From32(system); + return SvcWrap_StartThread64From32(system, args); case SvcId::ExitThread: - return SvcWrap_ExitThread64From32(system); + return SvcWrap_ExitThread64From32(system, args); case SvcId::SleepThread: - return SvcWrap_SleepThread64From32(system); + return SvcWrap_SleepThread64From32(system, args); case SvcId::GetThreadPriority: - return SvcWrap_GetThreadPriority64From32(system); + return SvcWrap_GetThreadPriority64From32(system, args); case SvcId::SetThreadPriority: - return SvcWrap_SetThreadPriority64From32(system); + return SvcWrap_SetThreadPriority64From32(system, args); case SvcId::GetThreadCoreMask: - return SvcWrap_GetThreadCoreMask64From32(system); + return SvcWrap_GetThreadCoreMask64From32(system, args); case SvcId::SetThreadCoreMask: - return SvcWrap_SetThreadCoreMask64From32(system); + return SvcWrap_SetThreadCoreMask64From32(system, args); case SvcId::GetCurrentProcessorNumber: - return SvcWrap_GetCurrentProcessorNumber64From32(system); + return SvcWrap_GetCurrentProcessorNumber64From32(system, args); case SvcId::SignalEvent: - return SvcWrap_SignalEvent64From32(system); + return SvcWrap_SignalEvent64From32(system, args); case SvcId::ClearEvent: - return SvcWrap_ClearEvent64From32(system); + return SvcWrap_ClearEvent64From32(system, args); case SvcId::MapSharedMemory: - return SvcWrap_MapSharedMemory64From32(system); + return SvcWrap_MapSharedMemory64From32(system, args); case SvcId::UnmapSharedMemory: - return SvcWrap_UnmapSharedMemory64From32(system); + return SvcWrap_UnmapSharedMemory64From32(system, args); case SvcId::CreateTransferMemory: - return SvcWrap_CreateTransferMemory64From32(system); + return SvcWrap_CreateTransferMemory64From32(system, args); case SvcId::CloseHandle: - return SvcWrap_CloseHandle64From32(system); + return SvcWrap_CloseHandle64From32(system, args); case SvcId::ResetSignal: - return SvcWrap_ResetSignal64From32(system); + return SvcWrap_ResetSignal64From32(system, args); case SvcId::WaitSynchronization: - return SvcWrap_WaitSynchronization64From32(system); + return SvcWrap_WaitSynchronization64From32(system, args); case SvcId::CancelSynchronization: - return SvcWrap_CancelSynchronization64From32(system); + return SvcWrap_CancelSynchronization64From32(system, args); case SvcId::ArbitrateLock: - return SvcWrap_ArbitrateLock64From32(system); + return SvcWrap_ArbitrateLock64From32(system, args); case SvcId::ArbitrateUnlock: - return SvcWrap_ArbitrateUnlock64From32(system); + return SvcWrap_ArbitrateUnlock64From32(system, args); case SvcId::WaitProcessWideKeyAtomic: - return SvcWrap_WaitProcessWideKeyAtomic64From32(system); + return SvcWrap_WaitProcessWideKeyAtomic64From32(system, args); case SvcId::SignalProcessWideKey: - return SvcWrap_SignalProcessWideKey64From32(system); + return SvcWrap_SignalProcessWideKey64From32(system, args); case SvcId::GetSystemTick: - return SvcWrap_GetSystemTick64From32(system); + return SvcWrap_GetSystemTick64From32(system, args); case SvcId::ConnectToNamedPort: - return SvcWrap_ConnectToNamedPort64From32(system); + return SvcWrap_ConnectToNamedPort64From32(system, args); case SvcId::SendSyncRequestLight: - return SvcWrap_SendSyncRequestLight64From32(system); + return SvcWrap_SendSyncRequestLight64From32(system, args); case SvcId::SendSyncRequest: - return SvcWrap_SendSyncRequest64From32(system); + return SvcWrap_SendSyncRequest64From32(system, args); case SvcId::SendSyncRequestWithUserBuffer: - return SvcWrap_SendSyncRequestWithUserBuffer64From32(system); + return SvcWrap_SendSyncRequestWithUserBuffer64From32(system, args); case SvcId::SendAsyncRequestWithUserBuffer: - return SvcWrap_SendAsyncRequestWithUserBuffer64From32(system); + return SvcWrap_SendAsyncRequestWithUserBuffer64From32(system, args); case SvcId::GetProcessId: - return SvcWrap_GetProcessId64From32(system); + return SvcWrap_GetProcessId64From32(system, args); case SvcId::GetThreadId: - return SvcWrap_GetThreadId64From32(system); + return SvcWrap_GetThreadId64From32(system, args); case SvcId::Break: - return SvcWrap_Break64From32(system); + return SvcWrap_Break64From32(system, args); case SvcId::OutputDebugString: - return SvcWrap_OutputDebugString64From32(system); + return SvcWrap_OutputDebugString64From32(system, args); case SvcId::ReturnFromException: - return SvcWrap_ReturnFromException64From32(system); + return SvcWrap_ReturnFromException64From32(system, args); case SvcId::GetInfo: - return SvcWrap_GetInfo64From32(system); + return SvcWrap_GetInfo64From32(system, args); case SvcId::FlushEntireDataCache: - return SvcWrap_FlushEntireDataCache64From32(system); + return SvcWrap_FlushEntireDataCache64From32(system, args); case SvcId::FlushDataCache: - return SvcWrap_FlushDataCache64From32(system); + return SvcWrap_FlushDataCache64From32(system, args); case SvcId::MapPhysicalMemory: - return SvcWrap_MapPhysicalMemory64From32(system); + return SvcWrap_MapPhysicalMemory64From32(system, args); case SvcId::UnmapPhysicalMemory: - return SvcWrap_UnmapPhysicalMemory64From32(system); + return SvcWrap_UnmapPhysicalMemory64From32(system, args); case SvcId::GetDebugFutureThreadInfo: - return SvcWrap_GetDebugFutureThreadInfo64From32(system); + return SvcWrap_GetDebugFutureThreadInfo64From32(system, args); case SvcId::GetLastThreadInfo: - return SvcWrap_GetLastThreadInfo64From32(system); + return SvcWrap_GetLastThreadInfo64From32(system, args); case SvcId::GetResourceLimitLimitValue: - return SvcWrap_GetResourceLimitLimitValue64From32(system); + return SvcWrap_GetResourceLimitLimitValue64From32(system, args); case SvcId::GetResourceLimitCurrentValue: - return SvcWrap_GetResourceLimitCurrentValue64From32(system); + return SvcWrap_GetResourceLimitCurrentValue64From32(system, args); case SvcId::SetThreadActivity: - return SvcWrap_SetThreadActivity64From32(system); + return SvcWrap_SetThreadActivity64From32(system, args); case SvcId::GetThreadContext3: - return SvcWrap_GetThreadContext364From32(system); + return SvcWrap_GetThreadContext364From32(system, args); case SvcId::WaitForAddress: - return SvcWrap_WaitForAddress64From32(system); + return SvcWrap_WaitForAddress64From32(system, args); case SvcId::SignalToAddress: - return SvcWrap_SignalToAddress64From32(system); + return SvcWrap_SignalToAddress64From32(system, args); case SvcId::SynchronizePreemptionState: - return SvcWrap_SynchronizePreemptionState64From32(system); + return SvcWrap_SynchronizePreemptionState64From32(system, args); case SvcId::GetResourceLimitPeakValue: - return SvcWrap_GetResourceLimitPeakValue64From32(system); + return SvcWrap_GetResourceLimitPeakValue64From32(system, args); case SvcId::CreateIoPool: - return SvcWrap_CreateIoPool64From32(system); + return SvcWrap_CreateIoPool64From32(system, args); case SvcId::CreateIoRegion: - return SvcWrap_CreateIoRegion64From32(system); + return SvcWrap_CreateIoRegion64From32(system, args); case SvcId::KernelDebug: - return SvcWrap_KernelDebug64From32(system); + return SvcWrap_KernelDebug64From32(system, args); case SvcId::ChangeKernelTraceState: - return SvcWrap_ChangeKernelTraceState64From32(system); + return SvcWrap_ChangeKernelTraceState64From32(system, args); case SvcId::CreateSession: - return SvcWrap_CreateSession64From32(system); + return SvcWrap_CreateSession64From32(system, args); case SvcId::AcceptSession: - return SvcWrap_AcceptSession64From32(system); + return SvcWrap_AcceptSession64From32(system, args); case SvcId::ReplyAndReceiveLight: - return SvcWrap_ReplyAndReceiveLight64From32(system); + return SvcWrap_ReplyAndReceiveLight64From32(system, args); case SvcId::ReplyAndReceive: - return SvcWrap_ReplyAndReceive64From32(system); + return SvcWrap_ReplyAndReceive64From32(system, args); case SvcId::ReplyAndReceiveWithUserBuffer: - return SvcWrap_ReplyAndReceiveWithUserBuffer64From32(system); + return SvcWrap_ReplyAndReceiveWithUserBuffer64From32(system, args); case SvcId::CreateEvent: - return SvcWrap_CreateEvent64From32(system); + return SvcWrap_CreateEvent64From32(system, args); case SvcId::MapIoRegion: - return SvcWrap_MapIoRegion64From32(system); + return SvcWrap_MapIoRegion64From32(system, args); case SvcId::UnmapIoRegion: - return SvcWrap_UnmapIoRegion64From32(system); + return SvcWrap_UnmapIoRegion64From32(system, args); case SvcId::MapPhysicalMemoryUnsafe: - return SvcWrap_MapPhysicalMemoryUnsafe64From32(system); + return SvcWrap_MapPhysicalMemoryUnsafe64From32(system, args); case SvcId::UnmapPhysicalMemoryUnsafe: - return SvcWrap_UnmapPhysicalMemoryUnsafe64From32(system); + return SvcWrap_UnmapPhysicalMemoryUnsafe64From32(system, args); case SvcId::SetUnsafeLimit: - return SvcWrap_SetUnsafeLimit64From32(system); + return SvcWrap_SetUnsafeLimit64From32(system, args); case SvcId::CreateCodeMemory: - return SvcWrap_CreateCodeMemory64From32(system); + return SvcWrap_CreateCodeMemory64From32(system, args); case SvcId::ControlCodeMemory: - return SvcWrap_ControlCodeMemory64From32(system); + return SvcWrap_ControlCodeMemory64From32(system, args); case SvcId::SleepSystem: - return SvcWrap_SleepSystem64From32(system); + return SvcWrap_SleepSystem64From32(system, args); case SvcId::ReadWriteRegister: - return SvcWrap_ReadWriteRegister64From32(system); + return SvcWrap_ReadWriteRegister64From32(system, args); case SvcId::SetProcessActivity: - return SvcWrap_SetProcessActivity64From32(system); + return SvcWrap_SetProcessActivity64From32(system, args); case SvcId::CreateSharedMemory: - return SvcWrap_CreateSharedMemory64From32(system); + return SvcWrap_CreateSharedMemory64From32(system, args); case SvcId::MapTransferMemory: - return SvcWrap_MapTransferMemory64From32(system); + return SvcWrap_MapTransferMemory64From32(system, args); case SvcId::UnmapTransferMemory: - return SvcWrap_UnmapTransferMemory64From32(system); + return SvcWrap_UnmapTransferMemory64From32(system, args); case SvcId::CreateInterruptEvent: - return SvcWrap_CreateInterruptEvent64From32(system); + return SvcWrap_CreateInterruptEvent64From32(system, args); case SvcId::QueryPhysicalAddress: - return SvcWrap_QueryPhysicalAddress64From32(system); + return SvcWrap_QueryPhysicalAddress64From32(system, args); case SvcId::QueryIoMapping: - return SvcWrap_QueryIoMapping64From32(system); + return SvcWrap_QueryIoMapping64From32(system, args); case SvcId::CreateDeviceAddressSpace: - return SvcWrap_CreateDeviceAddressSpace64From32(system); + return SvcWrap_CreateDeviceAddressSpace64From32(system, args); case SvcId::AttachDeviceAddressSpace: - return SvcWrap_AttachDeviceAddressSpace64From32(system); + return SvcWrap_AttachDeviceAddressSpace64From32(system, args); case SvcId::DetachDeviceAddressSpace: - return SvcWrap_DetachDeviceAddressSpace64From32(system); + return SvcWrap_DetachDeviceAddressSpace64From32(system, args); case SvcId::MapDeviceAddressSpaceByForce: - return SvcWrap_MapDeviceAddressSpaceByForce64From32(system); + return SvcWrap_MapDeviceAddressSpaceByForce64From32(system, args); case SvcId::MapDeviceAddressSpaceAligned: - return SvcWrap_MapDeviceAddressSpaceAligned64From32(system); + return SvcWrap_MapDeviceAddressSpaceAligned64From32(system, args); case SvcId::UnmapDeviceAddressSpace: - return SvcWrap_UnmapDeviceAddressSpace64From32(system); + return SvcWrap_UnmapDeviceAddressSpace64From32(system, args); case SvcId::InvalidateProcessDataCache: - return SvcWrap_InvalidateProcessDataCache64From32(system); + return SvcWrap_InvalidateProcessDataCache64From32(system, args); case SvcId::StoreProcessDataCache: - return SvcWrap_StoreProcessDataCache64From32(system); + return SvcWrap_StoreProcessDataCache64From32(system, args); case SvcId::FlushProcessDataCache: - return SvcWrap_FlushProcessDataCache64From32(system); + return SvcWrap_FlushProcessDataCache64From32(system, args); case SvcId::DebugActiveProcess: - return SvcWrap_DebugActiveProcess64From32(system); + return SvcWrap_DebugActiveProcess64From32(system, args); case SvcId::BreakDebugProcess: - return SvcWrap_BreakDebugProcess64From32(system); + return SvcWrap_BreakDebugProcess64From32(system, args); case SvcId::TerminateDebugProcess: - return SvcWrap_TerminateDebugProcess64From32(system); + return SvcWrap_TerminateDebugProcess64From32(system, args); case SvcId::GetDebugEvent: - return SvcWrap_GetDebugEvent64From32(system); + return SvcWrap_GetDebugEvent64From32(system, args); case SvcId::ContinueDebugEvent: - return SvcWrap_ContinueDebugEvent64From32(system); + return SvcWrap_ContinueDebugEvent64From32(system, args); case SvcId::GetProcessList: - return SvcWrap_GetProcessList64From32(system); + return SvcWrap_GetProcessList64From32(system, args); case SvcId::GetThreadList: - return SvcWrap_GetThreadList64From32(system); + return SvcWrap_GetThreadList64From32(system, args); case SvcId::GetDebugThreadContext: - return SvcWrap_GetDebugThreadContext64From32(system); + return SvcWrap_GetDebugThreadContext64From32(system, args); case SvcId::SetDebugThreadContext: - return SvcWrap_SetDebugThreadContext64From32(system); + return SvcWrap_SetDebugThreadContext64From32(system, args); case SvcId::QueryDebugProcessMemory: - return SvcWrap_QueryDebugProcessMemory64From32(system); + return SvcWrap_QueryDebugProcessMemory64From32(system, args); case SvcId::ReadDebugProcessMemory: - return SvcWrap_ReadDebugProcessMemory64From32(system); + return SvcWrap_ReadDebugProcessMemory64From32(system, args); case SvcId::WriteDebugProcessMemory: - return SvcWrap_WriteDebugProcessMemory64From32(system); + return SvcWrap_WriteDebugProcessMemory64From32(system, args); case SvcId::SetHardwareBreakPoint: - return SvcWrap_SetHardwareBreakPoint64From32(system); + return SvcWrap_SetHardwareBreakPoint64From32(system, args); case SvcId::GetDebugThreadParam: - return SvcWrap_GetDebugThreadParam64From32(system); + return SvcWrap_GetDebugThreadParam64From32(system, args); case SvcId::GetSystemInfo: - return SvcWrap_GetSystemInfo64From32(system); + return SvcWrap_GetSystemInfo64From32(system, args); case SvcId::CreatePort: - return SvcWrap_CreatePort64From32(system); + return SvcWrap_CreatePort64From32(system, args); case SvcId::ManageNamedPort: - return SvcWrap_ManageNamedPort64From32(system); + return SvcWrap_ManageNamedPort64From32(system, args); case SvcId::ConnectToPort: - return SvcWrap_ConnectToPort64From32(system); + return SvcWrap_ConnectToPort64From32(system, args); case SvcId::SetProcessMemoryPermission: - return SvcWrap_SetProcessMemoryPermission64From32(system); + return SvcWrap_SetProcessMemoryPermission64From32(system, args); case SvcId::MapProcessMemory: - return SvcWrap_MapProcessMemory64From32(system); + return SvcWrap_MapProcessMemory64From32(system, args); case SvcId::UnmapProcessMemory: - return SvcWrap_UnmapProcessMemory64From32(system); + return SvcWrap_UnmapProcessMemory64From32(system, args); case SvcId::QueryProcessMemory: - return SvcWrap_QueryProcessMemory64From32(system); + return SvcWrap_QueryProcessMemory64From32(system, args); case SvcId::MapProcessCodeMemory: - return SvcWrap_MapProcessCodeMemory64From32(system); + return SvcWrap_MapProcessCodeMemory64From32(system, args); case SvcId::UnmapProcessCodeMemory: - return SvcWrap_UnmapProcessCodeMemory64From32(system); + return SvcWrap_UnmapProcessCodeMemory64From32(system, args); case SvcId::CreateProcess: - return SvcWrap_CreateProcess64From32(system); + return SvcWrap_CreateProcess64From32(system, args); case SvcId::StartProcess: - return SvcWrap_StartProcess64From32(system); + return SvcWrap_StartProcess64From32(system, args); case SvcId::TerminateProcess: - return SvcWrap_TerminateProcess64From32(system); + return SvcWrap_TerminateProcess64From32(system, args); case SvcId::GetProcessInfo: - return SvcWrap_GetProcessInfo64From32(system); + return SvcWrap_GetProcessInfo64From32(system, args); case SvcId::CreateResourceLimit: - return SvcWrap_CreateResourceLimit64From32(system); + return SvcWrap_CreateResourceLimit64From32(system, args); case SvcId::SetResourceLimitLimitValue: - return SvcWrap_SetResourceLimitLimitValue64From32(system); + return SvcWrap_SetResourceLimitLimitValue64From32(system, args); case SvcId::CallSecureMonitor: - return SvcWrap_CallSecureMonitor64From32(system); + return SvcWrap_CallSecureMonitor64From32(system, args); case SvcId::MapInsecureMemory: - return SvcWrap_MapInsecureMemory64From32(system); + return SvcWrap_MapInsecureMemory64From32(system, args); case SvcId::UnmapInsecureMemory: - return SvcWrap_UnmapInsecureMemory64From32(system); + return SvcWrap_UnmapInsecureMemory64From32(system, args); default: LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm); break; } } -static void Call64(Core::System& system, u32 imm) { +static void Call64(Core::System& system, u32 imm, std::span<uint64_t, 8> args) { switch (static_cast<SvcId>(imm)) { case SvcId::SetHeapSize: - return SvcWrap_SetHeapSize64(system); + return SvcWrap_SetHeapSize64(system, args); case SvcId::SetMemoryPermission: - return SvcWrap_SetMemoryPermission64(system); + return SvcWrap_SetMemoryPermission64(system, args); case SvcId::SetMemoryAttribute: - return SvcWrap_SetMemoryAttribute64(system); + return SvcWrap_SetMemoryAttribute64(system, args); case SvcId::MapMemory: - return SvcWrap_MapMemory64(system); + return SvcWrap_MapMemory64(system, args); case SvcId::UnmapMemory: - return SvcWrap_UnmapMemory64(system); + return SvcWrap_UnmapMemory64(system, args); case SvcId::QueryMemory: - return SvcWrap_QueryMemory64(system); + return SvcWrap_QueryMemory64(system, args); case SvcId::ExitProcess: - return SvcWrap_ExitProcess64(system); + return SvcWrap_ExitProcess64(system, args); case SvcId::CreateThread: - return SvcWrap_CreateThread64(system); + return SvcWrap_CreateThread64(system, args); case SvcId::StartThread: - return SvcWrap_StartThread64(system); + return SvcWrap_StartThread64(system, args); case SvcId::ExitThread: - return SvcWrap_ExitThread64(system); + return SvcWrap_ExitThread64(system, args); case SvcId::SleepThread: - return SvcWrap_SleepThread64(system); + return SvcWrap_SleepThread64(system, args); case SvcId::GetThreadPriority: - return SvcWrap_GetThreadPriority64(system); + return SvcWrap_GetThreadPriority64(system, args); case SvcId::SetThreadPriority: - return SvcWrap_SetThreadPriority64(system); + return SvcWrap_SetThreadPriority64(system, args); case SvcId::GetThreadCoreMask: - return SvcWrap_GetThreadCoreMask64(system); + return SvcWrap_GetThreadCoreMask64(system, args); case SvcId::SetThreadCoreMask: - return SvcWrap_SetThreadCoreMask64(system); + return SvcWrap_SetThreadCoreMask64(system, args); case SvcId::GetCurrentProcessorNumber: - return SvcWrap_GetCurrentProcessorNumber64(system); + return SvcWrap_GetCurrentProcessorNumber64(system, args); case SvcId::SignalEvent: - return SvcWrap_SignalEvent64(system); + return SvcWrap_SignalEvent64(system, args); case SvcId::ClearEvent: - return SvcWrap_ClearEvent64(system); + return SvcWrap_ClearEvent64(system, args); case SvcId::MapSharedMemory: - return SvcWrap_MapSharedMemory64(system); + return SvcWrap_MapSharedMemory64(system, args); case SvcId::UnmapSharedMemory: - return SvcWrap_UnmapSharedMemory64(system); + return SvcWrap_UnmapSharedMemory64(system, args); case SvcId::CreateTransferMemory: - return SvcWrap_CreateTransferMemory64(system); + return SvcWrap_CreateTransferMemory64(system, args); case SvcId::CloseHandle: - return SvcWrap_CloseHandle64(system); + return SvcWrap_CloseHandle64(system, args); case SvcId::ResetSignal: - return SvcWrap_ResetSignal64(system); + return SvcWrap_ResetSignal64(system, args); case SvcId::WaitSynchronization: - return SvcWrap_WaitSynchronization64(system); + return SvcWrap_WaitSynchronization64(system, args); case SvcId::CancelSynchronization: - return SvcWrap_CancelSynchronization64(system); + return SvcWrap_CancelSynchronization64(system, args); case SvcId::ArbitrateLock: - return SvcWrap_ArbitrateLock64(system); + return SvcWrap_ArbitrateLock64(system, args); case SvcId::ArbitrateUnlock: - return SvcWrap_ArbitrateUnlock64(system); + return SvcWrap_ArbitrateUnlock64(system, args); case SvcId::WaitProcessWideKeyAtomic: - return SvcWrap_WaitProcessWideKeyAtomic64(system); + return SvcWrap_WaitProcessWideKeyAtomic64(system, args); case SvcId::SignalProcessWideKey: - return SvcWrap_SignalProcessWideKey64(system); + return SvcWrap_SignalProcessWideKey64(system, args); case SvcId::GetSystemTick: - return SvcWrap_GetSystemTick64(system); + return SvcWrap_GetSystemTick64(system, args); case SvcId::ConnectToNamedPort: - return SvcWrap_ConnectToNamedPort64(system); + return SvcWrap_ConnectToNamedPort64(system, args); case SvcId::SendSyncRequestLight: - return SvcWrap_SendSyncRequestLight64(system); + return SvcWrap_SendSyncRequestLight64(system, args); case SvcId::SendSyncRequest: - return SvcWrap_SendSyncRequest64(system); + return SvcWrap_SendSyncRequest64(system, args); case SvcId::SendSyncRequestWithUserBuffer: - return SvcWrap_SendSyncRequestWithUserBuffer64(system); + return SvcWrap_SendSyncRequestWithUserBuffer64(system, args); case SvcId::SendAsyncRequestWithUserBuffer: - return SvcWrap_SendAsyncRequestWithUserBuffer64(system); + return SvcWrap_SendAsyncRequestWithUserBuffer64(system, args); case SvcId::GetProcessId: - return SvcWrap_GetProcessId64(system); + return SvcWrap_GetProcessId64(system, args); case SvcId::GetThreadId: - return SvcWrap_GetThreadId64(system); + return SvcWrap_GetThreadId64(system, args); case SvcId::Break: - return SvcWrap_Break64(system); + return SvcWrap_Break64(system, args); case SvcId::OutputDebugString: - return SvcWrap_OutputDebugString64(system); + return SvcWrap_OutputDebugString64(system, args); case SvcId::ReturnFromException: - return SvcWrap_ReturnFromException64(system); + return SvcWrap_ReturnFromException64(system, args); case SvcId::GetInfo: - return SvcWrap_GetInfo64(system); + return SvcWrap_GetInfo64(system, args); case SvcId::FlushEntireDataCache: - return SvcWrap_FlushEntireDataCache64(system); + return SvcWrap_FlushEntireDataCache64(system, args); case SvcId::FlushDataCache: - return SvcWrap_FlushDataCache64(system); + return SvcWrap_FlushDataCache64(system, args); case SvcId::MapPhysicalMemory: - return SvcWrap_MapPhysicalMemory64(system); + return SvcWrap_MapPhysicalMemory64(system, args); case SvcId::UnmapPhysicalMemory: - return SvcWrap_UnmapPhysicalMemory64(system); + return SvcWrap_UnmapPhysicalMemory64(system, args); case SvcId::GetDebugFutureThreadInfo: - return SvcWrap_GetDebugFutureThreadInfo64(system); + return SvcWrap_GetDebugFutureThreadInfo64(system, args); case SvcId::GetLastThreadInfo: - return SvcWrap_GetLastThreadInfo64(system); + return SvcWrap_GetLastThreadInfo64(system, args); case SvcId::GetResourceLimitLimitValue: - return SvcWrap_GetResourceLimitLimitValue64(system); + return SvcWrap_GetResourceLimitLimitValue64(system, args); case SvcId::GetResourceLimitCurrentValue: - return SvcWrap_GetResourceLimitCurrentValue64(system); + return SvcWrap_GetResourceLimitCurrentValue64(system, args); case SvcId::SetThreadActivity: - return SvcWrap_SetThreadActivity64(system); + return SvcWrap_SetThreadActivity64(system, args); case SvcId::GetThreadContext3: - return SvcWrap_GetThreadContext364(system); + return SvcWrap_GetThreadContext364(system, args); case SvcId::WaitForAddress: - return SvcWrap_WaitForAddress64(system); + return SvcWrap_WaitForAddress64(system, args); case SvcId::SignalToAddress: - return SvcWrap_SignalToAddress64(system); + return SvcWrap_SignalToAddress64(system, args); case SvcId::SynchronizePreemptionState: - return SvcWrap_SynchronizePreemptionState64(system); + return SvcWrap_SynchronizePreemptionState64(system, args); case SvcId::GetResourceLimitPeakValue: - return SvcWrap_GetResourceLimitPeakValue64(system); + return SvcWrap_GetResourceLimitPeakValue64(system, args); case SvcId::CreateIoPool: - return SvcWrap_CreateIoPool64(system); + return SvcWrap_CreateIoPool64(system, args); case SvcId::CreateIoRegion: - return SvcWrap_CreateIoRegion64(system); + return SvcWrap_CreateIoRegion64(system, args); case SvcId::KernelDebug: - return SvcWrap_KernelDebug64(system); + return SvcWrap_KernelDebug64(system, args); case SvcId::ChangeKernelTraceState: - return SvcWrap_ChangeKernelTraceState64(system); + return SvcWrap_ChangeKernelTraceState64(system, args); case SvcId::CreateSession: - return SvcWrap_CreateSession64(system); + return SvcWrap_CreateSession64(system, args); case SvcId::AcceptSession: - return SvcWrap_AcceptSession64(system); + return SvcWrap_AcceptSession64(system, args); case SvcId::ReplyAndReceiveLight: - return SvcWrap_ReplyAndReceiveLight64(system); + return SvcWrap_ReplyAndReceiveLight64(system, args); case SvcId::ReplyAndReceive: - return SvcWrap_ReplyAndReceive64(system); + return SvcWrap_ReplyAndReceive64(system, args); case SvcId::ReplyAndReceiveWithUserBuffer: - return SvcWrap_ReplyAndReceiveWithUserBuffer64(system); + return SvcWrap_ReplyAndReceiveWithUserBuffer64(system, args); case SvcId::CreateEvent: - return SvcWrap_CreateEvent64(system); + return SvcWrap_CreateEvent64(system, args); case SvcId::MapIoRegion: - return SvcWrap_MapIoRegion64(system); + return SvcWrap_MapIoRegion64(system, args); case SvcId::UnmapIoRegion: - return SvcWrap_UnmapIoRegion64(system); + return SvcWrap_UnmapIoRegion64(system, args); case SvcId::MapPhysicalMemoryUnsafe: - return SvcWrap_MapPhysicalMemoryUnsafe64(system); + return SvcWrap_MapPhysicalMemoryUnsafe64(system, args); case SvcId::UnmapPhysicalMemoryUnsafe: - return SvcWrap_UnmapPhysicalMemoryUnsafe64(system); + return SvcWrap_UnmapPhysicalMemoryUnsafe64(system, args); case SvcId::SetUnsafeLimit: - return SvcWrap_SetUnsafeLimit64(system); + return SvcWrap_SetUnsafeLimit64(system, args); case SvcId::CreateCodeMemory: - return SvcWrap_CreateCodeMemory64(system); + return SvcWrap_CreateCodeMemory64(system, args); case SvcId::ControlCodeMemory: - return SvcWrap_ControlCodeMemory64(system); + return SvcWrap_ControlCodeMemory64(system, args); case SvcId::SleepSystem: - return SvcWrap_SleepSystem64(system); + return SvcWrap_SleepSystem64(system, args); case SvcId::ReadWriteRegister: - return SvcWrap_ReadWriteRegister64(system); + return SvcWrap_ReadWriteRegister64(system, args); case SvcId::SetProcessActivity: - return SvcWrap_SetProcessActivity64(system); + return SvcWrap_SetProcessActivity64(system, args); case SvcId::CreateSharedMemory: - return SvcWrap_CreateSharedMemory64(system); + return SvcWrap_CreateSharedMemory64(system, args); case SvcId::MapTransferMemory: - return SvcWrap_MapTransferMemory64(system); + return SvcWrap_MapTransferMemory64(system, args); case SvcId::UnmapTransferMemory: - return SvcWrap_UnmapTransferMemory64(system); + return SvcWrap_UnmapTransferMemory64(system, args); case SvcId::CreateInterruptEvent: - return SvcWrap_CreateInterruptEvent64(system); + return SvcWrap_CreateInterruptEvent64(system, args); case SvcId::QueryPhysicalAddress: - return SvcWrap_QueryPhysicalAddress64(system); + return SvcWrap_QueryPhysicalAddress64(system, args); case SvcId::QueryIoMapping: - return SvcWrap_QueryIoMapping64(system); + return SvcWrap_QueryIoMapping64(system, args); case SvcId::CreateDeviceAddressSpace: - return SvcWrap_CreateDeviceAddressSpace64(system); + return SvcWrap_CreateDeviceAddressSpace64(system, args); case SvcId::AttachDeviceAddressSpace: - return SvcWrap_AttachDeviceAddressSpace64(system); + return SvcWrap_AttachDeviceAddressSpace64(system, args); case SvcId::DetachDeviceAddressSpace: - return SvcWrap_DetachDeviceAddressSpace64(system); + return SvcWrap_DetachDeviceAddressSpace64(system, args); case SvcId::MapDeviceAddressSpaceByForce: - return SvcWrap_MapDeviceAddressSpaceByForce64(system); + return SvcWrap_MapDeviceAddressSpaceByForce64(system, args); case SvcId::MapDeviceAddressSpaceAligned: - return SvcWrap_MapDeviceAddressSpaceAligned64(system); + return SvcWrap_MapDeviceAddressSpaceAligned64(system, args); case SvcId::UnmapDeviceAddressSpace: - return SvcWrap_UnmapDeviceAddressSpace64(system); + return SvcWrap_UnmapDeviceAddressSpace64(system, args); case SvcId::InvalidateProcessDataCache: - return SvcWrap_InvalidateProcessDataCache64(system); + return SvcWrap_InvalidateProcessDataCache64(system, args); case SvcId::StoreProcessDataCache: - return SvcWrap_StoreProcessDataCache64(system); + return SvcWrap_StoreProcessDataCache64(system, args); case SvcId::FlushProcessDataCache: - return SvcWrap_FlushProcessDataCache64(system); + return SvcWrap_FlushProcessDataCache64(system, args); case SvcId::DebugActiveProcess: - return SvcWrap_DebugActiveProcess64(system); + return SvcWrap_DebugActiveProcess64(system, args); case SvcId::BreakDebugProcess: - return SvcWrap_BreakDebugProcess64(system); + return SvcWrap_BreakDebugProcess64(system, args); case SvcId::TerminateDebugProcess: - return SvcWrap_TerminateDebugProcess64(system); + return SvcWrap_TerminateDebugProcess64(system, args); case SvcId::GetDebugEvent: - return SvcWrap_GetDebugEvent64(system); + return SvcWrap_GetDebugEvent64(system, args); case SvcId::ContinueDebugEvent: - return SvcWrap_ContinueDebugEvent64(system); + return SvcWrap_ContinueDebugEvent64(system, args); case SvcId::GetProcessList: - return SvcWrap_GetProcessList64(system); + return SvcWrap_GetProcessList64(system, args); case SvcId::GetThreadList: - return SvcWrap_GetThreadList64(system); + return SvcWrap_GetThreadList64(system, args); case SvcId::GetDebugThreadContext: - return SvcWrap_GetDebugThreadContext64(system); + return SvcWrap_GetDebugThreadContext64(system, args); case SvcId::SetDebugThreadContext: - return SvcWrap_SetDebugThreadContext64(system); + return SvcWrap_SetDebugThreadContext64(system, args); case SvcId::QueryDebugProcessMemory: - return SvcWrap_QueryDebugProcessMemory64(system); + return SvcWrap_QueryDebugProcessMemory64(system, args); case SvcId::ReadDebugProcessMemory: - return SvcWrap_ReadDebugProcessMemory64(system); + return SvcWrap_ReadDebugProcessMemory64(system, args); case SvcId::WriteDebugProcessMemory: - return SvcWrap_WriteDebugProcessMemory64(system); + return SvcWrap_WriteDebugProcessMemory64(system, args); case SvcId::SetHardwareBreakPoint: - return SvcWrap_SetHardwareBreakPoint64(system); + return SvcWrap_SetHardwareBreakPoint64(system, args); case SvcId::GetDebugThreadParam: - return SvcWrap_GetDebugThreadParam64(system); + return SvcWrap_GetDebugThreadParam64(system, args); case SvcId::GetSystemInfo: - return SvcWrap_GetSystemInfo64(system); + return SvcWrap_GetSystemInfo64(system, args); case SvcId::CreatePort: - return SvcWrap_CreatePort64(system); + return SvcWrap_CreatePort64(system, args); case SvcId::ManageNamedPort: - return SvcWrap_ManageNamedPort64(system); + return SvcWrap_ManageNamedPort64(system, args); case SvcId::ConnectToPort: - return SvcWrap_ConnectToPort64(system); + return SvcWrap_ConnectToPort64(system, args); case SvcId::SetProcessMemoryPermission: - return SvcWrap_SetProcessMemoryPermission64(system); + return SvcWrap_SetProcessMemoryPermission64(system, args); case SvcId::MapProcessMemory: - return SvcWrap_MapProcessMemory64(system); + return SvcWrap_MapProcessMemory64(system, args); case SvcId::UnmapProcessMemory: - return SvcWrap_UnmapProcessMemory64(system); + return SvcWrap_UnmapProcessMemory64(system, args); case SvcId::QueryProcessMemory: - return SvcWrap_QueryProcessMemory64(system); + return SvcWrap_QueryProcessMemory64(system, args); case SvcId::MapProcessCodeMemory: - return SvcWrap_MapProcessCodeMemory64(system); + return SvcWrap_MapProcessCodeMemory64(system, args); case SvcId::UnmapProcessCodeMemory: - return SvcWrap_UnmapProcessCodeMemory64(system); + return SvcWrap_UnmapProcessCodeMemory64(system, args); case SvcId::CreateProcess: - return SvcWrap_CreateProcess64(system); + return SvcWrap_CreateProcess64(system, args); case SvcId::StartProcess: - return SvcWrap_StartProcess64(system); + return SvcWrap_StartProcess64(system, args); case SvcId::TerminateProcess: - return SvcWrap_TerminateProcess64(system); + return SvcWrap_TerminateProcess64(system, args); case SvcId::GetProcessInfo: - return SvcWrap_GetProcessInfo64(system); + return SvcWrap_GetProcessInfo64(system, args); case SvcId::CreateResourceLimit: - return SvcWrap_CreateResourceLimit64(system); + return SvcWrap_CreateResourceLimit64(system, args); case SvcId::SetResourceLimitLimitValue: - return SvcWrap_SetResourceLimitLimitValue64(system); + return SvcWrap_SetResourceLimitLimitValue64(system, args); case SvcId::CallSecureMonitor: - return SvcWrap_CallSecureMonitor64(system); + return SvcWrap_CallSecureMonitor64(system, args); case SvcId::MapInsecureMemory: - return SvcWrap_MapInsecureMemory64(system); + return SvcWrap_MapInsecureMemory64(system, args); case SvcId::UnmapInsecureMemory: - return SvcWrap_UnmapInsecureMemory64(system); + return SvcWrap_UnmapInsecureMemory64(system, args); default: LOG_CRITICAL(Kernel_SVC, "Unknown SVC {:x}!", imm); break; @@ -4424,15 +4424,20 @@ static void Call64(Core::System& system, u32 imm) { void Call(Core::System& system, u32 imm) { auto& kernel = system.Kernel(); + auto& process = GetCurrentProcess(kernel); + + std::array<uint64_t, 8> args; + kernel.CurrentPhysicalCore().SaveSvcArguments(process, args); kernel.EnterSVCProfile(); - if (GetCurrentProcess(system.Kernel()).Is64Bit()) { - Call64(system, imm); + if (process.Is64Bit()) { + Call64(system, imm, args); } else { - Call32(system, imm); + Call32(system, imm, args); } kernel.ExitSVCProfile(); + kernel.CurrentPhysicalCore().LoadSvcArguments(process, args); } } // 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 { class System; } +#include <span> + #include "common/common_types.h" #include "core/hle/kernel/svc_types.h" #include "core/hle/result.h" @@ -520,15 +522,15 @@ void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArgumen void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args); // Defined in svc_light_ipc.cpp. -void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system); -void SvcWrap_ReplyAndReceiveLight64(Core::System& system); +void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args); +void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args); -void SvcWrap_SendSyncRequestLight64From32(Core::System& system); -void SvcWrap_SendSyncRequestLight64(Core::System& system); +void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args); +void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args); // Defined in svc_secure_monitor_call.cpp. -void SvcWrap_CallSecureMonitor64From32(Core::System& system); -void SvcWrap_CallSecureMonitor64(Core::System& system); +void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args); +void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args); // Perform a supervisor call by index. void 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) { handle_debug_buffer(info1, info2); - auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); - const auto thread_processor_id = current_thread->GetActiveCore(); - system.ArmInterface(static_cast<std::size_t>(thread_processor_id)).LogBacktrace(); + system.CurrentPhysicalCore().LogBacktrace(); } 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 @@ #include "core/hle/kernel/k_client_session.h" #include "core/hle/kernel/k_hardware_timer.h" #include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_server_session.h" +#include "core/hle/kernel/k_session.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_results.h" namespace Kernel::Svc { -/// Makes a blocking IPC call to a service. -Result SendSyncRequest(Core::System& system, Handle handle) { - // Get the client session from its handle. +namespace { + +Result SendSyncRequestImpl(KernelCore& kernel, uintptr_t message, size_t buffer_size, + Handle session_handle) { + // Get the client session. KScopedAutoObject session = - GetCurrentProcess(system.Kernel()).GetHandleTable().GetObject<KClientSession>(handle); + GetCurrentProcess(kernel).GetHandleTable().GetObject<KClientSession>(session_handle); R_UNLESS(session.IsNotNull(), ResultInvalidHandle); - LOG_TRACE(Kernel_SVC, "called handle=0x{:08X}", handle); + // Get the parent, and persist a reference to it until we're done. + KScopedAutoObject parent = session->GetParent(); + ASSERT(parent.IsNotNull()); - R_RETURN(session->SendSyncRequest()); + // Send the request. + R_RETURN(session->SendSyncRequest(message, buffer_size)); } -Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message_buffer, - uint64_t message_buffer_size, Handle session_handle) { - UNIMPLEMENTED(); - R_THROW(ResultNotImplemented); -} +Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t message, + size_t buffer_size, KPhysicalAddress message_paddr, + KSynchronizationObject** objs, int32_t num_objects, Handle reply_target, + int64_t timeout_ns) { + // Reply to the target, if one is specified. + if (reply_target != InvalidHandle) { + KScopedAutoObject session = + GetCurrentProcess(kernel).GetHandleTable().GetObject<KServerSession>(reply_target); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); -Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, - uint64_t message_buffer, uint64_t message_buffer_size, - Handle session_handle) { - UNIMPLEMENTED(); - R_THROW(ResultNotImplemented); + // If we fail to reply, we want to set the output index to -1. + ON_RESULT_FAILURE { + *out_index = -1; + }; + + // Send the reply. + R_TRY(session->SendReply()); + // R_TRY(session->SendReply(message, buffer_size, message_paddr)); + } + + // Receive a message. + { + // Convert the timeout from nanoseconds to ticks. + // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... + s64 timeout; + if (timeout_ns > 0) { + const s64 offset_tick(timeout_ns); + if (offset_tick > 0) { + timeout = kernel.HardwareTimer().GetTick() + offset_tick + 2; + if (timeout <= 0) { + timeout = std::numeric_limits<s64>::max(); + } + } else { + timeout = std::numeric_limits<s64>::max(); + } + } else { + timeout = timeout_ns; + } + + // Wait for a message. + while (true) { + // Wait for an object. + s32 index; + Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs, + num_objects, timeout); + if (ResultTimedOut == result) { + R_THROW(result); + } + + // Receive the request. + if (R_SUCCEEDED(result)) { + KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); + if (session != nullptr) { + // result = session->ReceiveRequest(message, buffer_size, message_paddr); + result = session->ReceiveRequest(); + if (ResultNotFound == result) { + continue; + } + } + } + + *out_index = index; + R_RETURN(result); + } + } } -Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_addr, s32 num_handles, - Handle reply_target, s64 timeout_ns) { +Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t message, + size_t buffer_size, KPhysicalAddress message_paddr, + KProcessAddress user_handles, int32_t num_handles, Handle reply_target, + int64_t timeout_ns) { // Ensure number of handles is valid. - R_UNLESS(0 <= num_handles && num_handles <= ArgumentHandleCountMax, ResultOutOfRange); + R_UNLESS(0 <= num_handles && num_handles <= Svc::ArgumentHandleCountMax, ResultOutOfRange); // Get the synchronization context. - auto& kernel = system.Kernel(); - auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); - auto objs = GetCurrentThread(kernel).GetSynchronizationObjectBuffer(); - auto handles = GetCurrentThread(kernel).GetHandleBuffer(); + auto& process = GetCurrentProcess(kernel); + auto& thread = GetCurrentThread(kernel); + auto& handle_table = process.GetHandleTable(); + KSynchronizationObject** objs = thread.GetSynchronizationObjectBuffer().data(); + Handle* handles = thread.GetHandleBuffer().data(); // Copy user handles. if (num_handles > 0) { - // Get the handles. - R_UNLESS(GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), - sizeof(Handle) * num_handles), + // Ensure that we can try to get the handles. + R_UNLESS(process.GetPageTable().Contains(user_handles, num_handles * sizeof(Handle)), ResultInvalidPointer); + // Get the handles + R_UNLESS( + GetCurrentMemory(kernel).ReadBlock(user_handles, handles, sizeof(Handle) * num_handles), + ResultInvalidPointer); + // Convert the handles to objects. - R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>( - objs.data(), handles.data(), num_handles), - ResultInvalidHandle); + R_UNLESS( + handle_table.GetMultipleObjects<KSynchronizationObject>(objs, handles, num_handles), + ResultInvalidHandle); } // Ensure handles are closed when we're done. @@ -69,69 +137,135 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad } }); - // Reply to the target, if one is specified. - if (reply_target != InvalidHandle) { - KScopedAutoObject session = handle_table.GetObject<KServerSession>(reply_target); - R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + R_RETURN(ReplyAndReceiveImpl(kernel, out_index, message, buffer_size, message_paddr, objs, + num_handles, reply_target, timeout_ns)); +} - // If we fail to reply, we want to set the output index to -1. +} // namespace + +/// Makes a blocking IPC call to a service. +Result SendSyncRequest(Core::System& system, Handle session_handle) { + R_RETURN(SendSyncRequestImpl(system.Kernel(), 0, 0, session_handle)); +} + +Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message, uint64_t buffer_size, + Handle session_handle) { + auto& kernel = system.Kernel(); + + // Validate that the message buffer is page aligned and does not overflow. + R_UNLESS(Common::IsAligned(message, PageSize), ResultInvalidAddress); + R_UNLESS(buffer_size > 0, ResultInvalidSize); + R_UNLESS(Common::IsAligned(buffer_size, PageSize), ResultInvalidSize); + R_UNLESS(message < message + buffer_size, ResultInvalidCurrentMemory); + + // Get the process page table. + auto& page_table = GetCurrentProcess(kernel).GetPageTable(); + + // Lock the message buffer. + R_TRY(page_table.LockForIpcUserBuffer(nullptr, message, buffer_size)); + + { + // If we fail to send the message, unlock the message buffer. ON_RESULT_FAILURE { - *out_index = -1; + page_table.UnlockForIpcUserBuffer(message, buffer_size); }; - // Send the reply. - R_TRY(session->SendReply()); + // Send the request. + ASSERT(message != 0); + R_TRY(SendSyncRequestImpl(kernel, message, buffer_size, session_handle)); } - // Convert the timeout from nanoseconds to ticks. - // NOTE: Nintendo does not use this conversion logic in WaitSynchronization... - s64 timeout; - if (timeout_ns > 0) { - const s64 offset_tick(timeout_ns); - if (offset_tick > 0) { - timeout = kernel.HardwareTimer().GetTick() + offset_tick + 2; - if (timeout <= 0) { - timeout = std::numeric_limits<s64>::max(); - } - } else { - timeout = std::numeric_limits<s64>::max(); - } - } else { - timeout = timeout_ns; - } + // We successfully processed, so try to unlock the message buffer. + R_RETURN(page_table.UnlockForIpcUserBuffer(message, buffer_size)); +} - // Wait for a message. - while (true) { - // Wait for an object. - s32 index; - Result result = KSynchronizationObject::Wait(kernel, std::addressof(index), objs.data(), - num_handles, timeout); - if (result == ResultTimedOut) { - R_RETURN(result); - } +Result SendAsyncRequestWithUserBuffer(Core::System& system, Handle* out_event_handle, + uint64_t message, uint64_t buffer_size, + Handle session_handle) { + // Get the process and handle table. + auto& process = GetCurrentProcess(system.Kernel()); + auto& handle_table = process.GetHandleTable(); - // Receive the request. - if (R_SUCCEEDED(result)) { - KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); - if (session != nullptr) { - result = session->ReceiveRequest(); - if (result == ResultNotFound) { - continue; - } - } - } + // Reserve a new event from the process resource limit. + KScopedResourceReservation event_reservation(std::addressof(process), + Svc::LimitableResource::EventCountMax); + R_UNLESS(event_reservation.Succeeded(), ResultLimitReached); - *out_index = index; - R_RETURN(result); - } + // Get the client session. + KScopedAutoObject session = process.GetHandleTable().GetObject<KClientSession>(session_handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + + // Get the parent, and persist a reference to it until we're done. + KScopedAutoObject parent = session->GetParent(); + ASSERT(parent.IsNotNull()); + + // Create a new event. + KEvent* event = KEvent::Create(system.Kernel()); + R_UNLESS(event != nullptr, ResultOutOfResource); + + // Initialize the event. + event->Initialize(std::addressof(process)); + + // Commit our reservation. + event_reservation.Commit(); + + // At end of scope, kill the standing references to the sub events. + SCOPE_EXIT({ + event->GetReadableEvent().Close(); + event->Close(); + }); + + // Register the event. + KEvent::Register(system.Kernel(), event); + + // Add the readable event to the handle table. + R_TRY(handle_table.Add(out_event_handle, std::addressof(event->GetReadableEvent()))); + + // Ensure that if we fail to send the request, we close the readable handle. + ON_RESULT_FAILURE { + handle_table.Remove(*out_event_handle); + }; + + // Send the async request. + R_RETURN(session->SendAsyncRequest(event, message, buffer_size)); } -Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index, - uint64_t message_buffer, uint64_t message_buffer_size, - uint64_t handles, int32_t num_handles, Handle reply_target, - int64_t timeout_ns) { - UNIMPLEMENTED(); - R_THROW(ResultNotImplemented); +Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles, s32 num_handles, + Handle reply_target, s64 timeout_ns) { + R_RETURN(ReplyAndReceiveImpl(system.Kernel(), out_index, 0, 0, 0, handles, num_handles, + reply_target, timeout_ns)); +} + +Result ReplyAndReceiveWithUserBuffer(Core::System& system, int32_t* out_index, uint64_t message, + uint64_t buffer_size, uint64_t handles, int32_t num_handles, + Handle reply_target, int64_t timeout_ns) { + // Validate that the message buffer is page aligned and does not overflow. + R_UNLESS(Common::IsAligned(message, PageSize), ResultInvalidAddress); + R_UNLESS(buffer_size > 0, ResultInvalidSize); + R_UNLESS(Common::IsAligned(buffer_size, PageSize), ResultInvalidSize); + R_UNLESS(message < message + buffer_size, ResultInvalidCurrentMemory); + + // Get the process page table. + auto& page_table = GetCurrentProcess(system.Kernel()).GetPageTable(); + + // Lock the message buffer, getting its physical address. + KPhysicalAddress message_paddr; + R_TRY(page_table.LockForIpcUserBuffer(std::addressof(message_paddr), message, buffer_size)); + + { + // If we fail to send the message, unlock the message buffer. + ON_RESULT_FAILURE { + page_table.UnlockForIpcUserBuffer(message, buffer_size); + }; + + // Reply/Receive the request. + ASSERT(message != 0); + R_TRY(ReplyAndReceiveImpl(system.Kernel(), out_index, message, buffer_size, message_paddr, + handles, num_handles, reply_target, timeout_ns)); + } + + // We successfully processed, so try to unlock the message buffer. + R_RETURN(page_table.UnlockForIpcUserBuffer(message, buffer_size)); } Result 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 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/arm/arm_interface.h" #include "core/core.h" +#include "core/hle/kernel/k_light_client_session.h" +#include "core/hle/kernel/k_light_server_session.h" +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_results.h" namespace Kernel::Svc { Result SendSyncRequestLight(Core::System& system, Handle session_handle, u32* args) { - UNIMPLEMENTED(); - R_THROW(ResultNotImplemented); + // Get the light client session from its handle. + KScopedAutoObject session = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KLightClientSession>(session_handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + + // Send the request. + R_TRY(session->SendSyncRequest(args)); + + R_SUCCEED(); } Result ReplyAndReceiveLight(Core::System& system, Handle session_handle, u32* args) { - UNIMPLEMENTED(); - R_THROW(ResultNotImplemented); + // Get the light server session from its handle. + KScopedAutoObject session = GetCurrentProcess(system.Kernel()) + .GetHandleTable() + .GetObject<KLightServerSession>(session_handle); + R_UNLESS(session.IsNotNull(), ResultInvalidHandle); + + // Handle the request. + R_TRY(session->ReplyAndReceive(args)); + + R_SUCCEED(); } Result SendSyncRequestLight64(Core::System& system, Handle session_handle, u32* args) { @@ -37,37 +56,36 @@ Result ReplyAndReceiveLight64From32(Core::System& system, Handle session_handle, // Custom ABI implementation for light IPC. template <typename F> -static void SvcWrap_LightIpc(Core::System& system, F&& cb) { - auto& core = system.CurrentArmInterface(); - std::array<u32, 7> arguments{}; +static void SvcWrap_LightIpc(Core::System& system, std::span<uint64_t, 8> args, F&& cb) { + std::array<u32, 7> ipc_args{}; - Handle session_handle = static_cast<Handle>(core.GetReg(0)); + Handle session_handle = static_cast<Handle>(args[0]); for (int i = 0; i < 7; i++) { - arguments[i] = static_cast<u32>(core.GetReg(i + 1)); + ipc_args[i] = static_cast<u32>(args[i + 1]); } - Result ret = cb(system, session_handle, arguments.data()); + Result ret = cb(system, session_handle, ipc_args.data()); - core.SetReg(0, ret.raw); + args[0] = ret.raw; for (int i = 0; i < 7; i++) { - core.SetReg(i + 1, arguments[i]); + args[i + 1] = ipc_args[i]; } } -void SvcWrap_SendSyncRequestLight64(Core::System& system) { - SvcWrap_LightIpc(system, SendSyncRequestLight64); +void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args) { + SvcWrap_LightIpc(system, args, SendSyncRequestLight64); } -void SvcWrap_ReplyAndReceiveLight64(Core::System& system) { - SvcWrap_LightIpc(system, ReplyAndReceiveLight64); +void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args) { + SvcWrap_LightIpc(system, args, ReplyAndReceiveLight64); } -void SvcWrap_SendSyncRequestLight64From32(Core::System& system) { - SvcWrap_LightIpc(system, SendSyncRequestLight64From32); +void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args) { + SvcWrap_LightIpc(system, args, SendSyncRequestLight64From32); } -void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system) { - SvcWrap_LightIpc(system, ReplyAndReceiveLight64From32); +void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args) { + SvcWrap_LightIpc(system, args, ReplyAndReceiveLight64From32); } } // 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 @@ #include "core/core.h" #include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_light_client_session.h" #include "core/hle/kernel/k_object_name.h" #include "core/hle/kernel/k_port.h" #include "core/hle/kernel/k_process.h" @@ -51,13 +52,73 @@ Result ConnectToNamedPort(Core::System& system, Handle* out, u64 user_name) { Result CreatePort(Core::System& system, Handle* out_server, Handle* out_client, int32_t max_sessions, bool is_light, uint64_t name) { - UNIMPLEMENTED(); - R_THROW(ResultNotImplemented); + auto& kernel = system.Kernel(); + + // Ensure max sessions is valid. + R_UNLESS(max_sessions > 0, ResultOutOfRange); + + // Get the current handle table. + auto& handle_table = GetCurrentProcess(kernel).GetHandleTable(); + + // Create a new port. + KPort* port = KPort::Create(kernel); + R_UNLESS(port != nullptr, ResultOutOfResource); + + // Initialize the port. + port->Initialize(max_sessions, is_light, name); + + // Ensure that we clean up the port (and its only references are handle table) on function end. + SCOPE_EXIT({ + port->GetServerPort().Close(); + port->GetClientPort().Close(); + }); + + // Register the port. + KPort::Register(kernel, port); + + // Add the client to the handle table. + R_TRY(handle_table.Add(out_client, std::addressof(port->GetClientPort()))); + + // Ensure that we maintain a clean handle state on exit. + ON_RESULT_FAILURE { + handle_table.Remove(*out_client); + }; + + // Add the server to the handle table. + R_RETURN(handle_table.Add(out_server, std::addressof(port->GetServerPort()))); } -Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) { - UNIMPLEMENTED(); - R_THROW(ResultNotImplemented); +Result ConnectToPort(Core::System& system, Handle* out, Handle port) { + // Get the current handle table. + auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); + + // Get the client port. + KScopedAutoObject client_port = handle_table.GetObject<KClientPort>(port); + R_UNLESS(client_port.IsNotNull(), ResultInvalidHandle); + + // Reserve a handle for the port. + // NOTE: Nintendo really does write directly to the output handle here. + R_TRY(handle_table.Reserve(out)); + ON_RESULT_FAILURE { + handle_table.Unreserve(*out); + }; + + // Create the session. + KAutoObject* session; + if (client_port->IsLight()) { + R_TRY(client_port->CreateLightSession( + reinterpret_cast<KLightClientSession**>(std::addressof(session)))); + } else { + R_TRY(client_port->CreateSession( + reinterpret_cast<KClientSession**>(std::addressof(session)))); + } + + // Register the session. + handle_table.Register(*out, session); + session->Close(); + + // We succeeded. + R_SUCCEED(); } Result 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 // Custom ABI for CallSecureMonitor. -void SvcWrap_CallSecureMonitor64(Core::System& system) { - auto& core = system.CurrentPhysicalCore().ArmInterface(); - lp64::SecureMonitorArguments args{}; +void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args) { + lp64::SecureMonitorArguments smc_args{}; for (int i = 0; i < 8; i++) { - args.r[i] = core.GetReg(i); + smc_args.r[i] = args[i]; } - CallSecureMonitor64(system, std::addressof(args)); + CallSecureMonitor64(system, std::addressof(smc_args)); for (int i = 0; i < 8; i++) { - core.SetReg(i, args.r[i]); + args[i] = smc_args.r[i]; } } -void SvcWrap_CallSecureMonitor64From32(Core::System& system) { - auto& core = system.CurrentPhysicalCore().ArmInterface(); - ilp32::SecureMonitorArguments args{}; +void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args) { + ilp32::SecureMonitorArguments smc_args{}; for (int i = 0; i < 8; i++) { - args.r[i] = static_cast<u32>(core.GetReg(i)); + smc_args.r[i] = static_cast<u32>(args[i]); } - CallSecureMonitor64From32(system, std::addressof(args)); + CallSecureMonitor64From32(system, std::addressof(smc_args)); for (int i = 0; i < 8; i++) { - core.SetReg(i, args.r[i]); + args[i] = smc_args.r[i]; } } 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 @@ #include "common/scope_exit.h" #include "core/core.h" +#include "core/hle/kernel/k_light_session.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_session.h" #include "core/hle/kernel/svc.h" @@ -20,7 +22,7 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien T* session; // Reserve a new session from the process resource limit. - // FIXME: LimitableResource_SessionCountMax + // TODO: Dynamic resource limits KScopedResourceReservation session_reservation(std::addressof(process), LimitableResource::SessionCountMax); if (session_reservation.Succeeded()) { @@ -92,16 +94,42 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien Result CreateSession(Core::System& system, Handle* out_server, Handle* out_client, bool is_light, u64 name) { if (is_light) { - // return CreateSession<KLightSession>(system, out_server, out_client, name); - R_THROW(ResultNotImplemented); + R_RETURN(CreateSession<KLightSession>(system, out_server, out_client, name)); } else { R_RETURN(CreateSession<KSession>(system, out_server, out_client, name)); } } -Result AcceptSession(Core::System& system, Handle* out_handle, Handle port_handle) { - UNIMPLEMENTED(); - R_THROW(ResultNotImplemented); +Result AcceptSession(Core::System& system, Handle* out, Handle port_handle) { + // Get the current handle table. + auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); + + // Get the server port. + KScopedAutoObject port = handle_table.GetObject<KServerPort>(port_handle); + R_UNLESS(port.IsNotNull(), ResultInvalidHandle); + + // Reserve an entry for the new session. + R_TRY(handle_table.Reserve(out)); + ON_RESULT_FAILURE { + handle_table.Unreserve(*out); + }; + + // Accept the session. + KAutoObject* session; + if (port->IsLight()) { + session = port->AcceptLightSession(); + } else { + session = port->AcceptSession(); + } + + // Ensure we accepted successfully. + R_UNLESS(session != nullptr, ResultNotFound); + + // Register the session. + handle_table.Register(*out, session); + session->Close(); + + R_SUCCEED(); } Result 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) { /// Called when a thread exits void ExitThread(Core::System& system) { - LOG_DEBUG(Kernel_SVC, "called, pc=0x{:08X}", system.CurrentArmInterface().GetPC()); - auto* const current_thread = GetCurrentThreadPointer(system.Kernel()); system.GlobalSchedulerContext().RemoveThread(current_thread); current_thread->Exit(); @@ -147,47 +145,19 @@ Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_ha R_UNLESS(thread.IsNotNull(), ResultInvalidHandle); // Require the handle be to a non-current thread in the current process. - const auto* current_process = GetCurrentProcessPointer(kernel); - R_UNLESS(current_process == thread->GetOwnerProcess(), ResultInvalidId); - - // Verify that the thread isn't terminated. - R_UNLESS(thread->GetState() != ThreadState::Terminated, ResultTerminationRequested); - - /// Check that the thread is not the current one. - /// NOTE: Nintendo does not check this, and thus the following loop will deadlock. - R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultInvalidId); - - // Try to get the thread context until the thread isn't current on any core. - while (true) { - KScopedSchedulerLock sl{kernel}; - - // TODO(bunnei): Enforce that thread is suspended for debug here. - - // If the thread's raw state isn't runnable, check if it's current on some core. - if (thread->GetRawState() != ThreadState::Runnable) { - bool current = false; - for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { - if (thread.GetPointerUnsafe() == kernel.Scheduler(i).GetSchedulerCurrentThread()) { - current = true; - break; - } - } + R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(kernel), ResultInvalidHandle); + R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(kernel), ResultBusy); - // If the thread is current, retry until it isn't. - if (current) { - continue; - } - } + // Get the thread context. + Svc::ThreadContext context{}; + R_TRY(thread->GetThreadContext3(std::addressof(context))); - // Get the thread context. - static thread_local Common::ScratchBuffer<u8> context; - R_TRY(thread->GetThreadContext3(context)); + // Copy the thread context to user space. + R_UNLESS( + GetCurrentMemory(kernel).WriteBlock(out_context, std::addressof(context), sizeof(context)), + ResultInvalidPointer); - // Copy the thread context to user space. - GetCurrentMemory(kernel).WriteBlock(out_context, context.data(), context.size()); - - R_SUCCEED(); - } + R_SUCCEED(); } /// 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): # Collects possibly multiple source registers into the named C++ value. def emit_gather(sources, name, type_name, reg_size): - get_fn = f"GetReg{reg_size*8}" + get_fn = f"GetArg{reg_size*8}" if len(sources) == 1: s, = sources - line = f"{name} = Convert<{type_name}>({get_fn}(system, {s}));" + line = f"{name} = Convert<{type_name}>({get_fn}(args, {s}));" return [line] 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): ] for i in range(0, len(sources)): lines.append( - f"{name}_gather[{i}] = {get_fn}(system, {sources[i]});") + f"{name}_gather[{i}] = {get_fn}(args, {sources[i]});") lines.append(f"{name} = Convert<{type_name}>({name}_gather);") return lines @@ -396,12 +396,12 @@ def emit_gather(sources, name, type_name, reg_size): # Produces one or more statements which assign the named C++ value # into possibly multiple registers. def emit_scatter(destinations, name, reg_size): - set_fn = f"SetReg{reg_size*8}" + set_fn = f"SetArg{reg_size*8}" reg_type = f"uint{reg_size*8}_t" if len(destinations) == 1: d, = destinations - line = f"{set_fn}(system, {d}, Convert<{reg_type}>({name}));" + line = f"{set_fn}(args, {d}, Convert<{reg_type}>({name}));" return [line] var_type = f"std::array<{reg_type}, {len(destinations)}>" @@ -411,7 +411,7 @@ def emit_scatter(destinations, name, reg_size): for i in range(0, len(destinations)): lines.append( - f"{set_fn}(system, {destinations[i]}, {name}_scatter[{i}]);") + f"{set_fn}(args, {destinations[i]}, {name}_scatter[{i}]);") return lines @@ -433,7 +433,7 @@ def emit_lines(lines, indent=' '): def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size): return_write, output_writes, input_reads = register_info lines = [ - f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system) {{" + f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system, std::span<uint64_t, 8> args) {{" ] # Get everything ready. @@ -498,6 +498,8 @@ namespace Core { class System; } +#include <span> + #include "common/common_types.h" #include "core/hle/kernel/svc_types.h" #include "core/hle/result.h" @@ -524,15 +526,15 @@ void CallSecureMonitor64From32(Core::System& system, ilp32::SecureMonitorArgumen void CallSecureMonitor64(Core::System& system, lp64::SecureMonitorArguments* args); // Defined in svc_light_ipc.cpp. -void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system); -void SvcWrap_ReplyAndReceiveLight64(Core::System& system); +void SvcWrap_ReplyAndReceiveLight64From32(Core::System& system, std::span<uint64_t, 8> args); +void SvcWrap_ReplyAndReceiveLight64(Core::System& system, std::span<uint64_t, 8> args); -void SvcWrap_SendSyncRequestLight64From32(Core::System& system); -void SvcWrap_SendSyncRequestLight64(Core::System& system); +void SvcWrap_SendSyncRequestLight64From32(Core::System& system, std::span<uint64_t, 8> args); +void SvcWrap_SendSyncRequestLight64(Core::System& system, std::span<uint64_t, 8> args); // Defined in svc_secure_monitor_call.cpp. -void SvcWrap_CallSecureMonitor64From32(Core::System& system); -void SvcWrap_CallSecureMonitor64(Core::System& system); +void SvcWrap_CallSecureMonitor64From32(Core::System& system, std::span<uint64_t, 8> args); +void SvcWrap_CallSecureMonitor64(Core::System& system, std::span<uint64_t, 8> args); // Perform a supervisor call by index. void Call(Core::System& system, u32 imm); @@ -550,20 +552,20 @@ PROLOGUE_CPP = """ namespace Kernel::Svc { -static uint32_t GetReg32(Core::System& system, int n) { - return static_cast<uint32_t>(system.CurrentArmInterface().GetReg(n)); +static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) { + return static_cast<uint32_t>(args[n]); } -static void SetReg32(Core::System& system, int n, uint32_t result) { - system.CurrentArmInterface().SetReg(n, static_cast<uint64_t>(result)); +static void SetArg32(std::span<uint64_t, 8> args, int n, uint32_t result) { + args[n] = result; } -static uint64_t GetReg64(Core::System& system, int n) { - return system.CurrentArmInterface().GetReg(n); +static uint64_t GetArg64(std::span<uint64_t, 8> args, int n) { + return args[n]; } -static void SetReg64(Core::System& system, int n, uint64_t result) { - system.CurrentArmInterface().SetReg(n, result); +static void SetArg64(std::span<uint64_t, 8> args, int n, uint64_t result) { + args[n] = result; } // Like bit_cast, but handles the case when the source and dest @@ -590,15 +592,20 @@ EPILOGUE_CPP = """ void Call(Core::System& system, u32 imm) { auto& kernel = system.Kernel(); + auto& process = GetCurrentProcess(kernel); + + std::array<uint64_t, 8> args; + kernel.CurrentPhysicalCore().SaveSvcArguments(process, args); kernel.EnterSVCProfile(); - if (GetCurrentProcess(system.Kernel()).Is64Bit()) { - Call64(system, imm); + if (process.Is64Bit()) { + Call64(system, imm, args); } else { - Call32(system, imm); + Call32(system, imm, args); } kernel.ExitSVCProfile(); + kernel.CurrentPhysicalCore().LoadSvcArguments(process, args); } } // namespace Kernel::Svc @@ -609,13 +616,13 @@ def emit_call(bitness, names, suffix): bit_size = REG_SIZES[bitness]*8 indent = " " lines = [ - f"static void Call{bit_size}(Core::System& system, u32 imm) {{", + f"static void Call{bit_size}(Core::System& system, u32 imm, std::span<uint64_t, 8> args) {{", f"{indent}switch (static_cast<SvcId>(imm)) {{" ] for _, name in names: lines.append(f"{indent}case SvcId::{name}:") - lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system);") + lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system, args);") lines.append(f"{indent}default:") 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 entries.reserve(entries.size() + new_data.size()); for (const auto& new_entry : new_data) { - entries.emplace_back(new_entry->GetName(), type, + auto name = new_entry->GetName(); + + if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) { + continue; + } + + entries.emplace_back(name, type, type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize()); } } 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/service/hid/controllers/applet_resource.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" +#include "core/hle/service/hid/errors.h" + +namespace Service::HID { + +AppletResource::AppletResource(Core::System& system_) : system{system_} {} + +AppletResource::~AppletResource() = default; + +Result AppletResource::CreateAppletResource(u64 aruid) { + const u64 index = GetIndexFromAruid(aruid); + + if (index >= AruidIndexMax) { + return ResultAruidNotRegistered; + } + + if (data[index].flag.is_assigned) { + return ResultAruidAlreadyRegistered; + } + + auto& shared_memory = shared_memory_holder[index]; + if (!shared_memory.IsMapped()) { + const Result result = shared_memory.Initialize(system); + if (result.IsError()) { + return result; + } + if (shared_memory.GetAddress() == nullptr) { + shared_memory.Finalize(); + return ResultSharedMemoryNotInitialized; + } + } + + auto* shared_memory_format = shared_memory.GetAddress(); + if (shared_memory_format != nullptr) { + shared_memory_format->Initialize(); + } + + data[index].shared_memory_format = shared_memory_format; + data[index].flag.is_assigned.Assign(true); + // TODO: InitializeSixAxisControllerConfig(false); + active_aruid = aruid; + return ResultSuccess; +} + +Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input) { + const u64 index = GetIndexFromAruid(aruid); + + if (index < AruidIndexMax) { + return ResultAruidAlreadyRegistered; + } + + std::size_t data_index = AruidIndexMax; + for (std::size_t i = 0; i < AruidIndexMax; i++) { + if (!data[i].flag.is_initialized) { + data_index = i; + break; + } + } + + if (data_index == AruidIndexMax) { + return ResultAruidNoAvailableEntries; + } + + AruidData& aruid_data = data[data_index]; + + aruid_data.aruid = aruid; + aruid_data.flag.is_initialized.Assign(true); + if (enable_input) { + aruid_data.flag.enable_pad_input.Assign(true); + aruid_data.flag.enable_six_axis_sensor.Assign(true); + aruid_data.flag.bit_18.Assign(true); + aruid_data.flag.enable_touchscreen.Assign(true); + } + + data_index = AruidIndexMax; + for (std::size_t i = 0; i < AruidIndexMax; i++) { + if (registration_list.flag[i] == RegistrationStatus::Initialized) { + if (registration_list.aruid[i] != aruid) { + continue; + } + data_index = i; + break; + } + if (registration_list.flag[i] == RegistrationStatus::None) { + data_index = i; + break; + } + } + + if (data_index == AruidIndexMax) { + return ResultSuccess; + } + + registration_list.flag[data_index] = RegistrationStatus::Initialized; + registration_list.aruid[data_index] = aruid; + + return ResultSuccess; +} + +void AppletResource::UnregisterAppletResourceUserId(u64 aruid) { + u64 index = GetIndexFromAruid(aruid); + + if (index < AruidIndexMax) { + if (data[index].flag.is_assigned) { + data[index].shared_memory_format = nullptr; + data[index].flag.is_assigned.Assign(false); + } + } + + index = GetIndexFromAruid(aruid); + if (index < AruidIndexMax) { + DestroySevenSixAxisTransferMemory(); + data[index].flag.raw = 0; + data[index].aruid = 0; + + index = GetIndexFromAruid(aruid); + if (index < AruidIndexMax) { + registration_list.flag[index] = RegistrationStatus::PendingDelete; + } + } +} + +void AppletResource::FreeAppletResourceId(u64 aruid) { + u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return; + } + + auto& aruid_data = data[index]; + if (aruid_data.flag.is_assigned) { + aruid_data.shared_memory_format = nullptr; + aruid_data.flag.is_assigned.Assign(false); + } +} + +u64 AppletResource::GetActiveAruid() { + return active_aruid; +} + +Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { + u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return ResultAruidNotRegistered; + } + + *out_handle = shared_memory_holder[index].GetHandle(); + return ResultSuccess; +} + +Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, + u64 aruid) { + u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return ResultAruidNotRegistered; + } + + *out_shared_memory_format = data[index].shared_memory_format; + return ResultSuccess; +} + +u64 AppletResource::GetIndexFromAruid(u64 aruid) { + for (std::size_t i = 0; i < AruidIndexMax; i++) { + if (registration_list.flag[i] == RegistrationStatus::Initialized && + registration_list.aruid[i] == aruid) { + return i; + } + } + return AruidIndexMax; +} + +Result AppletResource::DestroySevenSixAxisTransferMemory() { + // TODO + return ResultSuccess; +} + +void AppletResource::EnableInput(u64 aruid, bool is_enabled) { + const u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return; + } + + data[index].flag.enable_pad_input.Assign(is_enabled); + data[index].flag.enable_touchscreen.Assign(is_enabled); +} + +void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) { + const u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return; + } + + data[index].flag.enable_six_axis_sensor.Assign(is_enabled); +} + +void AppletResource::EnablePadInput(u64 aruid, bool is_enabled) { + const u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return; + } + + data[index].flag.enable_pad_input.Assign(is_enabled); +} + +void AppletResource::EnableTouchScreen(u64 aruid, bool is_enabled) { + const u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return; + } + + data[index].flag.enable_touchscreen.Assign(is_enabled); +} + +void AppletResource::SetIsPalmaConnectable(u64 aruid, bool is_connectable) { + const u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return; + } + + data[index].flag.is_palma_connectable.Assign(is_connectable); +} + +void AppletResource::EnablePalmaBoostMode(u64 aruid, bool is_enabled) { + const u64 index = GetIndexFromAruid(aruid); + if (index >= AruidIndexMax) { + return; + } + + data[index].flag.enable_palma_boost_mode.Assign(is_enabled); +} + +Result AppletResource::RegisterCoreAppletResource() { + if (ref_counter == std::numeric_limits<s32>::max() - 1) { + return ResultAppletResourceOverflow; + } + if (ref_counter == 0) { + const u64 index = GetIndexFromAruid(0); + if (index < AruidIndexMax) { + return ResultAruidAlreadyRegistered; + } + + std::size_t data_index = AruidIndexMax; + for (std::size_t i = 0; i < AruidIndexMax; i++) { + if (!data[i].flag.is_initialized) { + data_index = i; + break; + } + } + + if (data_index == AruidIndexMax) { + return ResultAruidNoAvailableEntries; + } + + AruidData& aruid_data = data[data_index]; + + aruid_data.aruid = 0; + aruid_data.flag.is_initialized.Assign(true); + aruid_data.flag.enable_pad_input.Assign(true); + aruid_data.flag.enable_six_axis_sensor.Assign(true); + aruid_data.flag.bit_18.Assign(true); + aruid_data.flag.enable_touchscreen.Assign(true); + + data_index = AruidIndexMax; + for (std::size_t i = 0; i < AruidIndexMax; i++) { + if (registration_list.flag[i] == RegistrationStatus::Initialized) { + if (registration_list.aruid[i] != 0) { + continue; + } + data_index = i; + break; + } + if (registration_list.flag[i] == RegistrationStatus::None) { + data_index = i; + break; + } + } + + Result result = ResultSuccess; + + if (data_index == AruidIndexMax) { + result = CreateAppletResource(0); + } else { + registration_list.flag[data_index] = RegistrationStatus::Initialized; + registration_list.aruid[data_index] = 0; + } + + if (result.IsError()) { + UnregisterAppletResourceUserId(0); + return result; + } + } + ref_counter++; + return ResultSuccess; +} + +Result AppletResource::UnregisterCoreAppletResource() { + if (ref_counter == 0) { + return ResultAppletResourceNotInitialized; + } + + if (--ref_counter == 0) { + UnregisterAppletResourceUserId(0); + } + + return ResultSuccess; +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "core/hle/result.h" +#include "core/hle/service/hid/controllers/shared_memory_holder.h" + +namespace Core { +class System; +} + +namespace Kernel { +class KSharedMemory; +} + +namespace Service::HID { +struct SharedMemoryFormat; + +class AppletResource { +public: + explicit AppletResource(Core::System& system_); + ~AppletResource(); + + Result CreateAppletResource(u64 aruid); + + Result RegisterAppletResourceUserId(u64 aruid, bool enable_input); + void UnregisterAppletResourceUserId(u64 aruid); + + void FreeAppletResourceId(u64 aruid); + + u64 GetActiveAruid(); + Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); + Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid); + + u64 GetIndexFromAruid(u64 aruid); + + Result DestroySevenSixAxisTransferMemory(); + + void EnableInput(u64 aruid, bool is_enabled); + void EnableSixAxisSensor(u64 aruid, bool is_enabled); + void EnablePadInput(u64 aruid, bool is_enabled); + void EnableTouchScreen(u64 aruid, bool is_enabled); + void SetIsPalmaConnectable(u64 aruid, bool is_connectable); + void EnablePalmaBoostMode(u64 aruid, bool is_enabled); + + Result RegisterCoreAppletResource(); + Result UnregisterCoreAppletResource(); + +private: + static constexpr std::size_t AruidIndexMax = 0x20; + + enum RegistrationStatus : u32 { + None, + Initialized, + PendingDelete, + }; + + struct DataStatusFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> is_initialized; + BitField<1, 1, u32> is_assigned; + BitField<16, 1, u32> enable_pad_input; + BitField<17, 1, u32> enable_six_axis_sensor; + BitField<18, 1, u32> bit_18; + BitField<19, 1, u32> is_palma_connectable; + BitField<20, 1, u32> enable_palma_boost_mode; + BitField<21, 1, u32> enable_touchscreen; + }; + }; + + struct AruidRegisterList { + std::array<RegistrationStatus, AruidIndexMax> flag{}; + std::array<u64, AruidIndexMax> aruid{}; + }; + static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size"); + + struct AruidData { + DataStatusFlag flag{}; + u64 aruid{}; + SharedMemoryFormat* shared_memory_format{nullptr}; + }; + + u64 active_aruid{}; + AruidRegisterList registration_list{}; + std::array<AruidData, AruidIndexMax> data{}; + std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{}; + s32 ref_counter{}; + + Core::System& system; +}; +} // 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 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/core.h" #include "core/core_timing.h" #include "core/hid/emulated_console.h" #include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/console_six_axis.h" -#include "core/memory.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; -ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) - : ControllerBase{hid_core_} { +ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, + ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory) + : ControllerBase{hid_core_}, shared_memory{console_shared_memory} { console = hid_core.GetEmulatedConsole(); - static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size, - "ConsoleSharedMemory is bigger than the shared memory"); - shared_memory = std::construct_at( - reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); } ConsoleSixAxis::~ConsoleSixAxis() = default; @@ -33,10 +28,10 @@ void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { const auto motion_status = console->GetMotion(); - shared_memory->sampling_number++; - shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; - shared_memory->verticalization_error = motion_status.verticalization_error; - shared_memory->gyro_bias = motion_status.gyro_bias; + shared_memory.sampling_number++; + shared_memory.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; + shared_memory.verticalization_error = motion_status.verticalization_error; + shared_memory.gyro_bias = motion_status.gyro_bias; } } // 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 @@ #pragma once -#include "common/vector_math.h" #include "core/hle/service/hid/controllers/controller_base.h" namespace Core::HID { @@ -11,9 +10,12 @@ class EmulatedConsole; } // namespace Core::HID namespace Service::HID { +struct ConsoleSixAxisSensorSharedMemoryFormat; + class ConsoleSixAxis final : public ControllerBase { public: - explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, + ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory); ~ConsoleSixAxis() override; // Called when the controller is initialized @@ -26,18 +28,7 @@ public: void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: - // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat - struct ConsoleSharedMemory { - u64 sampling_number{}; - bool is_seven_six_axis_sensor_at_rest{}; - INSERT_PADDING_BYTES(3); // padding - f32 verticalization_error{}; - Common::Vec3f gyro_bias{}; - INSERT_PADDING_BYTES(4); // padding - }; - static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size"); - - ConsoleSharedMemory* shared_memory = nullptr; + ConsoleSixAxisSensorSharedMemoryFormat& shared_memory; Core::HID::EmulatedConsole* console = nullptr; }; } // 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: bool IsControllerActivated() const; - static const std::size_t hid_entry_count = 17; - static const std::size_t shared_memory_size = 0x40000; - protected: bool is_activated{false}; 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <cstring> -#include "common/common_types.h" #include "common/settings.h" #include "core/core_timing.h" #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/debug_pad.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; - -DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) - : ControllerBase{hid_core_} { - static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size, - "DebugPadSharedMemory is bigger than the shared memory"); - shared_memory = std::construct_at( - reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); + +DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, + DebugPadSharedMemoryFormat& debug_pad_shared_memory) + : ControllerBase{hid_core_}, shared_memory{debug_pad_shared_memory} { controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); } @@ -30,12 +25,12 @@ void DebugPad::OnRelease() {} void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - shared_memory->debug_pad_lifo.buffer_count = 0; - shared_memory->debug_pad_lifo.buffer_tail = 0; + shared_memory.debug_pad_lifo.buffer_count = 0; + shared_memory.debug_pad_lifo.buffer_tail = 0; return; } - const auto& last_entry = shared_memory->debug_pad_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.debug_pad_lifo.ReadCurrentEntry().state; next_state.sampling_number = last_entry.sampling_number + 1; if (Settings::values.debug_pad_enabled) { @@ -49,7 +44,7 @@ void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { next_state.r_stick = stick_state.right; } - shared_memory->debug_pad_lifo.WriteNextEntry(next_state); + shared_memory.debug_pad_lifo.WriteNextEntry(next_state); } } // 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 @@ #pragma once -#include "common/bit_field.h" -#include "common/common_types.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" +#include "core/hle/service/hid/controllers/types/debug_pad_types.h" namespace Core::HID { -class EmulatedController; -struct DebugPadButton; -struct AnalogStickState; -} // namespace Core::HID +class HIDCore; +} + +namespace Core::Timing { +class CoreTiming; +} namespace Service::HID { +struct DebugPadSharedMemoryFormat; + class DebugPad final : public ControllerBase { public: - explicit DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + explicit DebugPad(Core::HID::HIDCore& hid_core_, + DebugPadSharedMemoryFormat& debug_pad_shared_memory); ~DebugPad() override; // Called when the controller is initialized @@ -30,35 +33,8 @@ public: void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: - // This is nn::hid::DebugPadAttribute - struct DebugPadAttribute { - union { - u32 raw{}; - BitField<0, 1, u32> connected; - }; - }; - static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size"); - - // This is nn::hid::DebugPadState - struct DebugPadState { - s64 sampling_number{}; - DebugPadAttribute attribute{}; - Core::HID::DebugPadButton pad_state{}; - Core::HID::AnalogStickState r_stick{}; - Core::HID::AnalogStickState l_stick{}; - }; - static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); - - struct DebugPadSharedMemory { - // This is nn::hid::detail::DebugPadLifo - Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{}; - static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); - INSERT_PADDING_WORDS(0x4E); - }; - static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size"); - DebugPadState next_state{}; - DebugPadSharedMemory* shared_memory = nullptr; + DebugPadSharedMemoryFormat& shared_memory; Core::HID::EmulatedController* controller = nullptr; }; } // 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 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "common/logging/log.h" #include "common/math_util.h" #include "common/settings.h" -#include "core/core_timing.h" #include "core/frontend/emu_window.h" +#include "core/hid/emulated_console.h" #include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/gesture.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; - // HW is around 700, value is set to 400 to make it easier to trigger with mouse constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s constexpr f32 angle_threshold = 0.015f; // Threshold in radians @@ -23,19 +21,15 @@ constexpr f32 Square(s32 num) { return static_cast<f32>(num * num); } -Gesture::Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) - : ControllerBase(hid_core_) { - static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size, - "GestureSharedMemory is bigger than the shared memory"); - shared_memory = std::construct_at( - reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); +Gesture::Gesture(Core::HID::HIDCore& hid_core_, GestureSharedMemoryFormat& gesture_shared_memory) + : ControllerBase(hid_core_), shared_memory{gesture_shared_memory} { console = hid_core.GetEmulatedConsole(); } Gesture::~Gesture() = default; void Gesture::OnInit() { - shared_memory->gesture_lifo.buffer_count = 0; - shared_memory->gesture_lifo.buffer_tail = 0; + shared_memory.gesture_lifo.buffer_count = 0; + shared_memory.gesture_lifo.buffer_tail = 0; force_update = true; } @@ -43,8 +37,8 @@ void Gesture::OnRelease() {} void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - shared_memory->gesture_lifo.buffer_count = 0; - shared_memory->gesture_lifo.buffer_tail = 0; + shared_memory.gesture_lifo.buffer_count = 0; + shared_memory.gesture_lifo.buffer_tail = 0; return; } @@ -52,7 +46,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { GestureProperties gesture = GetGestureProperties(); f32 time_difference = - static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) / + static_cast<f32>(shared_memory.gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); // Only update if necessary @@ -60,7 +54,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { return; } - last_update_timestamp = shared_memory->gesture_lifo.timestamp; + last_update_timestamp = shared_memory.gesture_lifo.timestamp; UpdateGestureSharedMemory(gesture, time_difference); } @@ -103,7 +97,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif GestureType type = GestureType::Idle; GestureAttribute attributes{}; - const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.gesture_lifo.ReadCurrentEntry().state; // Reset next state to default next_state.sampling_number = last_entry.sampling_number + 1; @@ -133,7 +127,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif next_state.points = gesture.points; last_gesture = gesture; - shared_memory->gesture_lifo.WriteNextEntry(next_state); + shared_memory.gesture_lifo.WriteNextEntry(next_state); } void Gesture::NewGesture(GestureProperties& gesture, GestureType& type, @@ -305,11 +299,11 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_ next_state.direction = GestureDirection::Up; } -const Gesture::GestureState& Gesture::GetLastGestureEntry() const { - return shared_memory->gesture_lifo.ReadCurrentEntry().state; +const GestureState& Gesture::GetLastGestureEntry() const { + return shared_memory.gesture_lifo.ReadCurrentEntry().state; } -Gesture::GestureProperties Gesture::GetGestureProperties() { +GestureProperties Gesture::GetGestureProperties() { GestureProperties gesture; std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers; 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 @@ #pragma once #include <array> -#include "common/bit_field.h" + #include "common/common_types.h" -#include "common/point.h" -#include "core/hid/emulated_console.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" +#include "core/hle/service/hid/controllers/types/touch_types.h" + +namespace Core::HID { +class EmulatedConsole; +} namespace Service::HID { +struct GestureSharedMemoryFormat; + class Gesture final : public ControllerBase { public: - explicit Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + explicit Gesture(Core::HID::HIDCore& hid_core_, + GestureSharedMemoryFormat& gesture_shared_memory); ~Gesture() override; // Called when the controller is initialized @@ -27,79 +32,6 @@ public: void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: - static constexpr size_t MAX_FINGERS = 16; - static constexpr size_t MAX_POINTS = 4; - - // This is nn::hid::GestureType - enum class GestureType : u32 { - Idle, // Nothing touching the screen - Complete, // Set at the end of a touch event - Cancel, // Set when the number of fingers change - Touch, // A finger just touched the screen - Press, // Set if last type is touch and the finger hasn't moved - Tap, // Fast press then release - Pan, // All points moving together across the screen - Swipe, // Fast press movement and release of a single point - Pinch, // All points moving away/closer to the midpoint - Rotate, // All points rotating from the midpoint - }; - - // This is nn::hid::GestureDirection - enum class GestureDirection : u32 { - None, - Left, - Up, - Right, - Down, - }; - - // This is nn::hid::GestureAttribute - struct GestureAttribute { - union { - u32 raw{}; - - BitField<4, 1, u32> is_new_touch; - BitField<8, 1, u32> is_double_tap; - }; - }; - static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); - - // This is nn::hid::GestureState - struct GestureState { - s64 sampling_number{}; - s64 detection_count{}; - GestureType type{GestureType::Idle}; - GestureDirection direction{GestureDirection::None}; - Common::Point<s32> pos{}; - Common::Point<s32> delta{}; - f32 vel_x{}; - f32 vel_y{}; - GestureAttribute attributes{}; - f32 scale{}; - f32 rotation_angle{}; - s32 point_count{}; - std::array<Common::Point<s32>, 4> points{}; - }; - static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); - - struct GestureProperties { - std::array<Common::Point<s32>, MAX_POINTS> points{}; - std::size_t active_points{}; - Common::Point<s32> mid_point{}; - s64 detection_count{}; - u64 delta_time{}; - f32 average_distance{}; - f32 angle{}; - }; - - struct GestureSharedMemory { - // This is nn::hid::detail::GestureLifo - Lifo<GestureState, hid_entry_count> gesture_lifo{}; - static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); - INSERT_PADDING_WORDS(0x3E); - }; - static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size"); - // Reads input from all available input engines void ReadTouchInput(); @@ -142,7 +74,7 @@ private: GestureProperties GetGestureProperties(); GestureState next_state{}; - GestureSharedMemory* shared_memory = nullptr; + GestureSharedMemoryFormat& shared_memory; Core::HID::EmulatedConsole* console = nullptr; 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <cstring> -#include "common/common_types.h" #include "common/settings.h" #include "core/core_timing.h" #include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/keyboard.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; - -Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) - : ControllerBase{hid_core_} { - static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size, - "KeyboardSharedMemory is bigger than the shared memory"); - shared_memory = std::construct_at( - reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); + +Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, + KeyboardSharedMemoryFormat& keyboard_shared_memory) + : ControllerBase{hid_core_}, shared_memory{keyboard_shared_memory} { emulated_devices = hid_core.GetEmulatedDevices(); } @@ -29,12 +24,12 @@ void Keyboard::OnRelease() {} void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - shared_memory->keyboard_lifo.buffer_count = 0; - shared_memory->keyboard_lifo.buffer_tail = 0; + shared_memory.keyboard_lifo.buffer_count = 0; + shared_memory.keyboard_lifo.buffer_tail = 0; return; } - const auto& last_entry = shared_memory->keyboard_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.keyboard_lifo.ReadCurrentEntry().state; next_state.sampling_number = last_entry.sampling_number + 1; if (Settings::values.keyboard_enabled) { @@ -46,7 +41,7 @@ void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { next_state.attribute.is_connected.Assign(1); } - shared_memory->keyboard_lifo.WriteNextEntry(next_state); + shared_memory.keyboard_lifo.WriteNextEntry(next_state); } } // 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 @@ #pragma once -#include "common/common_types.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Core::HID { -class EmulatedDevices; -struct KeyboardModifier; -struct KeyboardKey; -} // namespace Core::HID +#include "core/hle/service/hid/controllers/types/keyboard_types.h" namespace Service::HID { +struct KeyboardSharedMemoryFormat; + class Keyboard final : public ControllerBase { public: - explicit Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + explicit Keyboard(Core::HID::HIDCore& hid_core_, + KeyboardSharedMemoryFormat& keyboard_shared_memory); ~Keyboard() override; // Called when the controller is initialized @@ -29,25 +25,8 @@ public: void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: - // This is nn::hid::detail::KeyboardState - struct KeyboardState { - s64 sampling_number{}; - Core::HID::KeyboardModifier modifier{}; - Core::HID::KeyboardAttribute attribute{}; - Core::HID::KeyboardKey key{}; - }; - static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); - - struct KeyboardSharedMemory { - // This is nn::hid::detail::KeyboardLifo - Lifo<KeyboardState, hid_entry_count> keyboard_lifo{}; - static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); - INSERT_PADDING_WORDS(0xA); - }; - static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size"); - KeyboardState next_state{}; - KeyboardSharedMemory* shared_memory = nullptr; + KeyboardSharedMemoryFormat& shared_memory; Core::HID::EmulatedDevices* emulated_devices = nullptr; }; } // 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <cstring> -#include "common/common_types.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/mouse.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; -Mouse::Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} { - static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size, - "MouseSharedMemory is bigger than the shared memory"); - shared_memory = std::construct_at( - reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); +Mouse::Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory) + : ControllerBase{hid_core_}, shared_memory{mouse_shared_memory} { emulated_devices = hid_core.GetEmulatedDevices(); } @@ -27,14 +22,14 @@ void Mouse::OnRelease() {} void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - shared_memory->mouse_lifo.buffer_count = 0; - shared_memory->mouse_lifo.buffer_tail = 0; + shared_memory.mouse_lifo.buffer_count = 0; + shared_memory.mouse_lifo.buffer_tail = 0; return; } next_state = {}; - const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state; next_state.sampling_number = last_entry.sampling_number + 1; if (Settings::values.mouse_enabled) { @@ -53,7 +48,7 @@ void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { next_state.button = mouse_button_state; } - shared_memory->mouse_lifo.WriteNextEntry(next_state); + shared_memory.mouse_lifo.WriteNextEntry(next_state); } } // 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 @@ #pragma once -#include "common/common_types.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" namespace Core::HID { class EmulatedDevices; @@ -14,9 +12,11 @@ struct AnalogStickState; } // namespace Core::HID namespace Service::HID { +struct MouseSharedMemoryFormat; + class Mouse final : public ControllerBase { public: - explicit Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory); ~Mouse() override; // Called when the controller is initialized @@ -29,17 +29,9 @@ public: void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: - struct MouseSharedMemory { - // This is nn::hid::detail::MouseLifo - Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{}; - static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); - INSERT_PADDING_WORDS(0x2C); - }; - static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size"); - Core::HID::MouseState next_state{}; Core::HID::AnalogStickState last_mouse_wheel_state{}; - MouseSharedMemory* shared_memory = nullptr; + MouseSharedMemoryFormat& shared_memory; Core::HID::EmulatedDevices* emulated_devices = nullptr; }; } // 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 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" #include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/hid_util.h" #include "core/hle/service/kernel_helpers.h" namespace Service::HID { -constexpr std::size_t NPAD_OFFSET = 0x9A00; constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{ Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, 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{ Core::HID::NpadIdType::Handheld, }; -NPad::NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, +NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format, KernelHelpers::ServiceContext& service_context_) : ControllerBase{hid_core_}, service_context{service_context_} { - static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size); for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; - controller.shared_memory = std::construct_at(reinterpret_cast<NpadInternalState*>( - raw_shared_memory_ + NPAD_OFFSET + (i * sizeof(NpadInternalState)))); + controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state; controller.device = hid_core.GetEmulatedControllerByIndex(i); controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE; @@ -617,7 +615,7 @@ void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { hold_type = joy_hold_type; } -NPad::NpadJoyHoldType NPad::GetHoldType() const { +NpadJoyHoldType NPad::GetHoldType() const { return hold_type; } @@ -630,7 +628,7 @@ void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_m handheld_activation_mode = activation_mode; } -NPad::NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const { +NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const { return handheld_activation_mode; } @@ -638,7 +636,7 @@ void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) { communication_mode = communication_mode_; } -NPad::NpadCommunicationMode NPad::GetNpadCommunicationMode() const { +NpadCommunicationMode NPad::GetNpadCommunicationMode() const { return communication_mode; } @@ -978,27 +976,27 @@ Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned( return ResultSuccess; } -NPad::SixAxisLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) { +NpadSixAxisSensorLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) { return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo; } -NPad::SixAxisLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) { +NpadSixAxisSensorLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) { return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo; } -NPad::SixAxisLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) { +NpadSixAxisSensorLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) { return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo; } -NPad::SixAxisLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) { +NpadSixAxisSensorLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) { return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo; } -NPad::SixAxisLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) { +NpadSixAxisSensorLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) { return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo; } -NPad::SixAxisLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) { +NpadSixAxisSensorLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) { return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo; } @@ -1343,7 +1341,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties( } } -NPad::AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) { +AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) { const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory; 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 @@ #include <mutex> #include <span> -#include "common/bit_field.h" #include "common/common_types.h" - #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" +#include "core/hle/service/hid/controllers/types/npad_types.h" namespace Core::HID { class EmulatedController; @@ -32,10 +30,13 @@ class ServiceContext; union Result; namespace Service::HID { +struct NpadInternalState; +struct NpadSixAxisSensorLifo; +struct NpadSharedMemoryFormat; class NPad final : public ControllerBase { public: - explicit NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, + explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format, KernelHelpers::ServiceContext& service_context_); ~NPad() override; @@ -48,89 +49,6 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - // This is nn::hid::NpadJoyHoldType - enum class NpadJoyHoldType : u64 { - Vertical = 0, - Horizontal = 1, - }; - - // This is nn::hid::NpadJoyAssignmentMode - enum class NpadJoyAssignmentMode : u32 { - Dual = 0, - Single = 1, - }; - - // This is nn::hid::NpadJoyDeviceType - enum class NpadJoyDeviceType : s64 { - Left = 0, - Right = 1, - }; - - // This is nn::hid::NpadHandheldActivationMode - enum class NpadHandheldActivationMode : u64 { - Dual = 0, - Single = 1, - None = 2, - MaxActivationMode = 3, - }; - - // This is nn::hid::system::AppletFooterUiAttributesSet - struct AppletFooterUiAttributes { - INSERT_PADDING_BYTES(0x4); - }; - - // This is nn::hid::system::AppletFooterUiType - enum class AppletFooterUiType : u8 { - None = 0, - HandheldNone = 1, - HandheldJoyConLeftOnly = 2, - HandheldJoyConRightOnly = 3, - HandheldJoyConLeftJoyConRight = 4, - JoyDual = 5, - JoyDualLeftOnly = 6, - JoyDualRightOnly = 7, - JoyLeftHorizontal = 8, - JoyLeftVertical = 9, - JoyRightHorizontal = 10, - JoyRightVertical = 11, - SwitchProController = 12, - CompatibleProController = 13, - CompatibleJoyCon = 14, - LarkHvc1 = 15, - LarkHvc2 = 16, - LarkNesLeft = 17, - LarkNesRight = 18, - Lucia = 19, - Verification = 20, - Lagon = 21, - }; - - using AppletFooterUiVariant = u8; - - // This is "nn::hid::system::AppletDetailedUiType". - struct AppletDetailedUiType { - AppletFooterUiVariant ui_variant; - INSERT_PADDING_BYTES(0x2); - AppletFooterUiType footer; - }; - static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size"); - // This is nn::hid::NpadCommunicationMode - enum class NpadCommunicationMode : u64 { - Mode_5ms = 0, - Mode_10ms = 1, - Mode_15ms = 2, - Default = 3, - }; - - enum class NpadRevision : u32 { - Revision0 = 0, - Revision1 = 1, - Revision2 = 2, - Revision3 = 3, - }; - - using SixAxisLifo = Lifo<Core::HID::SixAxisSensorState, hid_entry_count>; - void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); Core::HID::NpadStyleTag GetSupportedStyleSet() const; @@ -188,12 +106,12 @@ public: Result ResetIsSixAxisSensorDeviceNewlyAssigned( const Core::HID::SixAxisSensorHandle& sixaxis_handle); - SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id); - SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id); - SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id); - SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id); - SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id); - SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id); + NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id); + NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id); + NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id); + NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id); + NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id); + NpadSixAxisSensorLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id); Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const; Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id, @@ -221,214 +139,6 @@ public: AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id); private: - static constexpr std::size_t NPAD_COUNT = 10; - - // This is nn::hid::detail::ColorAttribute - enum class ColorAttribute : u32 { - Ok = 0, - ReadError = 1, - NoController = 2, - }; - static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size"); - - // This is nn::hid::detail::NpadFullKeyColorState - struct NpadFullKeyColorState { - ColorAttribute attribute{ColorAttribute::NoController}; - Core::HID::NpadControllerColor fullkey{}; - }; - static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size"); - - // This is nn::hid::detail::NpadJoyColorState - struct NpadJoyColorState { - ColorAttribute attribute{ColorAttribute::NoController}; - Core::HID::NpadControllerColor left{}; - Core::HID::NpadControllerColor right{}; - }; - static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size"); - - // This is nn::hid::NpadAttribute - struct NpadAttribute { - union { - u32 raw{}; - BitField<0, 1, u32> is_connected; - BitField<1, 1, u32> is_wired; - BitField<2, 1, u32> is_left_connected; - BitField<3, 1, u32> is_left_wired; - BitField<4, 1, u32> is_right_connected; - BitField<5, 1, u32> is_right_wired; - }; - }; - static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size"); - - // This is nn::hid::NpadFullKeyState - // This is nn::hid::NpadHandheldState - // This is nn::hid::NpadJoyDualState - // This is nn::hid::NpadJoyLeftState - // This is nn::hid::NpadJoyRightState - // This is nn::hid::NpadPalmaState - // This is nn::hid::NpadSystemExtState - struct NPadGenericState { - s64_le sampling_number{}; - Core::HID::NpadButtonState npad_buttons{}; - Core::HID::AnalogStickState l_stick{}; - Core::HID::AnalogStickState r_stick{}; - NpadAttribute connection_status{}; - INSERT_PADDING_BYTES(4); // Reserved - }; - static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); - - // This is nn::hid::server::NpadGcTriggerState - struct NpadGcTriggerState { - s64 sampling_number{}; - s32 l_analog{}; - s32 r_analog{}; - }; - static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); - - // This is nn::hid::NpadSystemProperties - struct NPadSystemProperties { - union { - s64 raw{}; - BitField<0, 1, s64> is_charging_joy_dual; - BitField<1, 1, s64> is_charging_joy_left; - BitField<2, 1, s64> is_charging_joy_right; - BitField<3, 1, s64> is_powered_joy_dual; - BitField<4, 1, s64> is_powered_joy_left; - BitField<5, 1, s64> is_powered_joy_right; - BitField<9, 1, s64> is_system_unsupported_button; - BitField<10, 1, s64> is_system_ext_unsupported_button; - BitField<11, 1, s64> is_vertical; - BitField<12, 1, s64> is_horizontal; - BitField<13, 1, s64> use_plus; - BitField<14, 1, s64> use_minus; - BitField<15, 1, s64> use_directional_buttons; - }; - }; - static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); - - // This is nn::hid::NpadSystemButtonProperties - struct NpadSystemButtonProperties { - union { - s32 raw{}; - BitField<0, 1, s32> is_home_button_protection_enabled; - }; - }; - static_assert(sizeof(NpadSystemButtonProperties) == 0x4, - "NPadButtonProperties is an invalid size"); - - // This is nn::hid::system::DeviceType - struct DeviceType { - union { - u32 raw{}; - BitField<0, 1, s32> fullkey; - BitField<1, 1, s32> debug_pad; - BitField<2, 1, s32> handheld_left; - BitField<3, 1, s32> handheld_right; - BitField<4, 1, s32> joycon_left; - BitField<5, 1, s32> joycon_right; - BitField<6, 1, s32> palma; - BitField<7, 1, s32> lark_hvc_left; - BitField<8, 1, s32> lark_hvc_right; - BitField<9, 1, s32> lark_nes_left; - BitField<10, 1, s32> lark_nes_right; - BitField<11, 1, s32> handheld_lark_hvc_left; - BitField<12, 1, s32> handheld_lark_hvc_right; - BitField<13, 1, s32> handheld_lark_nes_left; - BitField<14, 1, s32> handheld_lark_nes_right; - BitField<15, 1, s32> lucia; - BitField<16, 1, s32> lagon; - BitField<17, 1, s32> lager; - BitField<31, 1, s32> system; - }; - }; - - // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl - struct NfcXcdDeviceHandleStateImpl { - u64 handle{}; - bool is_available{}; - bool is_activated{}; - INSERT_PADDING_BYTES(0x6); // Reserved - u64 sampling_number{}; - }; - static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, - "NfcXcdDeviceHandleStateImpl is an invalid size"); - - // This is nn::hid::NpadLarkType - enum class NpadLarkType : u32 { - Invalid, - H1, - H2, - NL, - NR, - }; - - // This is nn::hid::NpadLuciaType - enum class NpadLuciaType : u32 { - Invalid, - J, - E, - U, - }; - - // This is nn::hid::NpadLagonType - enum class NpadLagonType : u32 { - Invalid, - }; - - // This is nn::hid::NpadLagerType - enum class NpadLagerType : u32 { - Invalid, - J, - E, - U, - }; - - // This is nn::hid::detail::NpadInternalState - struct NpadInternalState { - Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None}; - NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual}; - NpadFullKeyColorState fullkey_color{}; - NpadJoyColorState joycon_color{}; - Lifo<NPadGenericState, hid_entry_count> fullkey_lifo{}; - Lifo<NPadGenericState, hid_entry_count> handheld_lifo{}; - Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo{}; - Lifo<NPadGenericState, hid_entry_count> joy_left_lifo{}; - Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{}; - Lifo<NPadGenericState, hid_entry_count> palma_lifo{}; - Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{}; - Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{}; - Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{}; - Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{}; - Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{}; - Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{}; - Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{}; - DeviceType device_type{}; - INSERT_PADDING_BYTES(0x4); // Reserved - NPadSystemProperties system_properties{}; - NpadSystemButtonProperties button_properties{}; - Core::HID::NpadBatteryLevel battery_level_dual{}; - Core::HID::NpadBatteryLevel battery_level_left{}; - Core::HID::NpadBatteryLevel battery_level_right{}; - AppletFooterUiAttributes applet_footer_attributes{}; - AppletFooterUiType applet_footer_type{AppletFooterUiType::None}; - INSERT_PADDING_BYTES(0x5B); // Reserved - INSERT_PADDING_BYTES(0x20); // Unknown - Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{}; - NpadLarkType lark_type_l_and_main{}; - NpadLarkType lark_type_r{}; - NpadLuciaType lucia_type{}; - NpadLagonType lagon_type{}; - NpadLagerType lager_type{}; - Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties; - Core::HID::SixAxisSensorProperties sixaxis_handheld_properties; - Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties; - Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties; - Core::HID::SixAxisSensorProperties sixaxis_left_properties; - Core::HID::SixAxisSensorProperties sixaxis_right_properties; - INSERT_PADDING_BYTES(0xc06); // Unknown - }; - static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); - struct VibrationData { bool device_mounted{}; Core::HID::VibrationValue latest_vibration_value{}; @@ -479,7 +189,7 @@ private: std::atomic<u64> press_state{}; - std::array<NpadControllerData, NPAD_COUNT> controller_data{}; + std::array<NpadControllerData, NpadCount> controller_data{}; KernelHelpers::ServiceContext& service_context; std::mutex mutex; 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 @@ namespace Service::HID { -Palma::Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, - KernelHelpers::ServiceContext& service_context_) +Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) : ControllerBase{hid_core_}, service_context{service_context_} { controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); 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: static_assert(sizeof(PalmaConnectionHandle) == 0x8, "PalmaConnectionHandle has incorrect size."); - explicit Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, - KernelHelpers::ServiceContext& service_context_); + explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_); ~Palma() override; // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/vector_math.h" +#include "core/hid/hid_types.h" +#include "core/hle/service/hid//controllers/types/debug_pad_types.h" +#include "core/hle/service/hid//controllers/types/keyboard_types.h" +#include "core/hle/service/hid//controllers/types/mouse_types.h" +#include "core/hle/service/hid//controllers/types/npad_types.h" +#include "core/hle/service/hid//controllers/types/touch_types.h" +#include "core/hle/service/hid/ring_lifo.h" + +namespace Service::HID { +static const std::size_t HidEntryCount = 17; + +struct CommonHeader { + s64 timestamp{}; + s64 total_entry_count{}; + s64 last_entry_index{}; + s64 entry_count{}; +}; +static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + +// This is nn::hid::detail::DebugPadSharedMemoryFormat +struct DebugPadSharedMemoryFormat { + // This is nn::hid::detail::DebugPadLifo + Lifo<DebugPadState, HidEntryCount> debug_pad_lifo{}; + static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); + INSERT_PADDING_WORDS(0x4E); +}; +static_assert(sizeof(DebugPadSharedMemoryFormat) == 0x400, + "DebugPadSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::TouchScreenSharedMemoryFormat +struct TouchScreenSharedMemoryFormat { + // This is nn::hid::detail::TouchScreenLifo + Lifo<TouchScreenState, HidEntryCount> touch_screen_lifo{}; + static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); + INSERT_PADDING_WORDS(0xF2); +}; +static_assert(sizeof(TouchScreenSharedMemoryFormat) == 0x3000, + "TouchScreenSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::MouseSharedMemoryFormat +struct MouseSharedMemoryFormat { + // This is nn::hid::detail::MouseLifo + Lifo<Core::HID::MouseState, HidEntryCount> mouse_lifo{}; + static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); + INSERT_PADDING_WORDS(0x2C); +}; +static_assert(sizeof(MouseSharedMemoryFormat) == 0x400, + "MouseSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::KeyboardSharedMemoryFormat +struct KeyboardSharedMemoryFormat { + // This is nn::hid::detail::KeyboardLifo + Lifo<KeyboardState, HidEntryCount> keyboard_lifo{}; + static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); + INSERT_PADDING_WORDS(0xA); +}; +static_assert(sizeof(KeyboardSharedMemoryFormat) == 0x400, + "KeyboardSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::DigitizerSharedMemoryFormat +struct DigitizerSharedMemoryFormat { + CommonHeader header; + INSERT_PADDING_BYTES(0xFE0); +}; +static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000, + "DigitizerSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::HomeButtonSharedMemoryFormat +struct HomeButtonSharedMemoryFormat { + CommonHeader header; + INSERT_PADDING_BYTES(0x1E0); +}; +static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200, + "HomeButtonSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::SleepButtonSharedMemoryFormat +struct SleepButtonSharedMemoryFormat { + CommonHeader header; + INSERT_PADDING_BYTES(0x1E0); +}; +static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200, + "SleepButtonSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::CaptureButtonSharedMemoryFormat +struct CaptureButtonSharedMemoryFormat { + CommonHeader header; + INSERT_PADDING_BYTES(0x1E0); +}; +static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200, + "CaptureButtonSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::InputDetectorSharedMemoryFormat +struct InputDetectorSharedMemoryFormat { + CommonHeader header; + INSERT_PADDING_BYTES(0x7E0); +}; +static_assert(sizeof(InputDetectorSharedMemoryFormat) == 0x800, + "InputDetectorSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::UniquePadSharedMemoryFormat +struct UniquePadSharedMemoryFormat { + CommonHeader header; + INSERT_PADDING_BYTES(0x3FE0); +}; +static_assert(sizeof(UniquePadSharedMemoryFormat) == 0x4000, + "UniquePadSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::NpadSixAxisSensorLifo +struct NpadSixAxisSensorLifo { + Lifo<Core::HID::SixAxisSensorState, HidEntryCount> lifo; +}; + +// This is nn::hid::detail::NpadInternalState +struct NpadInternalState { + Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None}; + NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual}; + NpadFullKeyColorState fullkey_color{}; + NpadJoyColorState joycon_color{}; + Lifo<NPadGenericState, HidEntryCount> fullkey_lifo{}; + Lifo<NPadGenericState, HidEntryCount> handheld_lifo{}; + Lifo<NPadGenericState, HidEntryCount> joy_dual_lifo{}; + Lifo<NPadGenericState, HidEntryCount> joy_left_lifo{}; + Lifo<NPadGenericState, HidEntryCount> joy_right_lifo{}; + Lifo<NPadGenericState, HidEntryCount> palma_lifo{}; + Lifo<NPadGenericState, HidEntryCount> system_ext_lifo{}; + NpadSixAxisSensorLifo sixaxis_fullkey_lifo{}; + NpadSixAxisSensorLifo sixaxis_handheld_lifo{}; + NpadSixAxisSensorLifo sixaxis_dual_left_lifo{}; + NpadSixAxisSensorLifo sixaxis_dual_right_lifo{}; + NpadSixAxisSensorLifo sixaxis_left_lifo{}; + NpadSixAxisSensorLifo sixaxis_right_lifo{}; + DeviceType device_type{}; + INSERT_PADDING_BYTES(0x4); // Reserved + NPadSystemProperties system_properties{}; + NpadSystemButtonProperties button_properties{}; + Core::HID::NpadBatteryLevel battery_level_dual{}; + Core::HID::NpadBatteryLevel battery_level_left{}; + Core::HID::NpadBatteryLevel battery_level_right{}; + AppletFooterUiAttributes applet_footer_attributes{}; + AppletFooterUiType applet_footer_type{AppletFooterUiType::None}; + INSERT_PADDING_BYTES(0x5B); // Reserved + INSERT_PADDING_BYTES(0x20); // Unknown + Lifo<NpadGcTriggerState, HidEntryCount> gc_trigger_lifo{}; + NpadLarkType lark_type_l_and_main{}; + NpadLarkType lark_type_r{}; + NpadLuciaType lucia_type{}; + NpadLagerType lager_type{}; + Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties; + Core::HID::SixAxisSensorProperties sixaxis_handheld_properties; + Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties; + Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties; + Core::HID::SixAxisSensorProperties sixaxis_left_properties; + Core::HID::SixAxisSensorProperties sixaxis_right_properties; +}; +static_assert(sizeof(NpadInternalState) == 0x43F8, "NpadInternalState is an invalid size"); + +// This is nn::hid::detail::NpadSharedMemoryEntry +struct NpadSharedMemoryEntry { + NpadInternalState internal_state; + INSERT_PADDING_BYTES(0xC08); +}; +static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is an invalid size"); + +// This is nn::hid::detail::NpadSharedMemoryFormat +struct NpadSharedMemoryFormat { + std::array<NpadSharedMemoryEntry, NpadCount> npad_entry; +}; +static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000, + "NpadSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::GestureSharedMemoryFormat +struct GestureSharedMemoryFormat { + // This is nn::hid::detail::GestureLifo + Lifo<GestureState, HidEntryCount> gesture_lifo{}; + static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); + INSERT_PADDING_WORDS(0x3E); +}; +static_assert(sizeof(GestureSharedMemoryFormat) == 0x800, + "GestureSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat +struct ConsoleSixAxisSensorSharedMemoryFormat { + u64 sampling_number{}; + bool is_seven_six_axis_sensor_at_rest{}; + INSERT_PADDING_BYTES(3); // padding + f32 verticalization_error{}; + Common::Vec3f gyro_bias{}; + INSERT_PADDING_BYTES(4); // padding +}; +static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20, + "ConsoleSixAxisSensorSharedMemoryFormat is an invalid size"); + +// This is nn::hid::detail::SharedMemoryFormat +struct SharedMemoryFormat { + void Initialize() {} + + DebugPadSharedMemoryFormat debug_pad; + TouchScreenSharedMemoryFormat touch_screen; + MouseSharedMemoryFormat mouse; + KeyboardSharedMemoryFormat keyboard; + DigitizerSharedMemoryFormat digitizer; + HomeButtonSharedMemoryFormat home_button; + SleepButtonSharedMemoryFormat sleep_button; + CaptureButtonSharedMemoryFormat capture_button; + InputDetectorSharedMemoryFormat input_detector; + UniquePadSharedMemoryFormat unique_pad; + NpadSharedMemoryFormat npad; + GestureSharedMemoryFormat gesture; + ConsoleSixAxisSensorSharedMemoryFormat console; + INSERT_PADDING_BYTES(0x19E0); + MouseSharedMemoryFormat debug_mouse; + INSERT_PADDING_BYTES(0x2000); +}; +static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, mouse) == 0x3400, "mouse has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, keyboard) == 0x3800, "keyboard has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, digitizer) == 0x3C00, "digitizer has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, home_button) == 0x4C00, "home_button has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, sleep_button) == 0x4E00, + "sleep_button has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, capture_button) == 0x5000, + "capture_button has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, input_detector) == 0x5200, + "input_detector has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset"); +static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset"); +static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size"); + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "core/core.h" +#include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" +#include "core/hle/service/hid/controllers/shared_memory_holder.h" +#include "core/hle/service/hid/errors.h" + +namespace Service::HID { +SharedMemoryHolder::SharedMemoryHolder() {} + +SharedMemoryHolder::~SharedMemoryHolder() { + Finalize(); +} + +Result SharedMemoryHolder::Initialize(Core::System& system) { + shared_memory = Kernel::KSharedMemory::Create(system.Kernel()); + const Result result = shared_memory->Initialize( + system.DeviceMemory(), nullptr, Kernel::Svc::MemoryPermission::None, + Kernel::Svc::MemoryPermission::Read, sizeof(SharedMemoryFormat)); + if (result.IsError()) { + return result; + } + Kernel::KSharedMemory::Register(system.Kernel(), shared_memory); + + is_created = true; + is_mapped = true; + address = std::construct_at(reinterpret_cast<SharedMemoryFormat*>(shared_memory->GetPointer())); + return ResultSuccess; +} + +void SharedMemoryHolder::Finalize() { + if (address != nullptr) { + shared_memory->Close(); + } + is_created = false; + is_mapped = false; + address = nullptr; +} + +bool SharedMemoryHolder::IsMapped() { + return is_mapped; +} + +SharedMemoryFormat* SharedMemoryHolder::GetAddress() { + return address; +} + +Kernel::KSharedMemory* SharedMemoryHolder::GetHandle() { + return shared_memory; +} +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/result.h" + +namespace Core { +class System; +} + +namespace Kernel { +class KSharedMemory; +} + +namespace Service::HID { +struct SharedMemoryFormat; + +// This is nn::hid::detail::SharedMemoryHolder +class SharedMemoryHolder { +public: + SharedMemoryHolder(); + ~SharedMemoryHolder(); + + Result Initialize(Core::System& system); + void Finalize(); + + bool IsMapped(); + SharedMemoryFormat* GetAddress(); + Kernel::KSharedMemory* GetHandle(); + +private: + bool is_owner{}; + bool is_created{}; + bool is_mapped{}; + INSERT_PADDING_BYTES(0x5); + Kernel::KSharedMemory* shared_memory; + INSERT_PADDING_BYTES(0x38); + SharedMemoryFormat* address = nullptr; +}; +// Correct size is 0x50 bytes +static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size"); + +} // 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 @@ #include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" #include "core/hle/service/hid/controllers/six_axis.h" #include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/hid_util.h" @@ -132,30 +133,30 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { } sixaxis_fullkey_state.sampling_number = - sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_handheld_state.sampling_number = - sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_left_state.sampling_number = - sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_right_state.sampling_number = - sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_left_lifo_state.sampling_number = - sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_right_lifo_state.sampling_number = - sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1; if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { // This buffer only is updated on handheld on HW - sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); + sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state); } else { // Handheld doesn't update this buffer on HW - sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); + sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state); } - sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); - sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); - sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); - sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); + sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state); + sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state); + sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state); + sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state); } } 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <cstring> -#include "common/common_types.h" #include "core/core_timing.h" -#include "core/hid/hid_core.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" #include "core/hle/service/hid/controllers/stubbed.h" namespace Service::HID { -Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) - : ControllerBase{hid_core_} { - raw_shared_memory = raw_shared_memory_; -} +Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, + CommonHeader& ring_lifo_header) + : ControllerBase{hid_core_}, header{ring_lifo_header} {} Controller_Stubbed::~Controller_Stubbed() = default; @@ -25,18 +22,10 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) { return; } - CommonHeader header{}; header.timestamp = core_timing.GetGlobalTimeNs().count(); header.total_entry_count = 17; header.entry_count = 0; header.last_entry_index = 0; - - std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader)); -} - -void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { - common_offset = off; - smart_update = true; } } // 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 @@ #pragma once -#include "common/common_types.h" #include "core/hle/service/hid/controllers/controller_base.h" namespace Service::HID { +struct CommonHeader; + class Controller_Stubbed final : public ControllerBase { public: - explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, CommonHeader& ring_lifo_header); ~Controller_Stubbed() override; // Called when the controller is initialized @@ -21,19 +22,8 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - void SetCommonHeaderOffset(std::size_t off); - private: - struct CommonHeader { - s64 timestamp{}; - s64 total_entry_count{}; - s64 last_entry_index{}; - s64 entry_count{}; - }; - static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - - u8* raw_shared_memory = nullptr; + CommonHeader& header; bool smart_update{}; - std::size_t common_offset{}; }; } // 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 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <algorithm> -#include <cstring> #include "common/common_types.h" #include "common/settings.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" #include "core/hid/emulated_console.h" #include "core/hid/hid_core.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" #include "core/hle/service/hid/controllers/touchscreen.h" namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) - : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width), +TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, + TouchScreenSharedMemoryFormat& touch_shared_memory) + : ControllerBase{hid_core_}, shared_memory{touch_shared_memory}, + touchscreen_width(Layout::ScreenUndocked::Width), touchscreen_height(Layout::ScreenUndocked::Height) { - static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size, - "TouchSharedMemory is bigger than the shared memory"); - shared_memory = std::construct_at( - reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); console = hid_core.GetEmulatedConsole(); } @@ -32,11 +28,11 @@ void TouchScreen::OnInit() {} void TouchScreen::OnRelease() {} void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); + shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count(); if (!IsControllerActivated()) { - shared_memory->touch_screen_lifo.buffer_count = 0; - shared_memory->touch_screen_lifo.buffer_tail = 0; + shared_memory.touch_screen_lifo.buffer_count = 0; + shared_memory.touch_screen_lifo.buffer_tail = 0; return; } @@ -86,7 +82,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count()); - const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state; next_state.sampling_number = last_entry.sampling_number + 1; next_state.entry_count = static_cast<s32>(active_fingers_count); @@ -118,7 +114,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { } } - shared_memory->touch_screen_lifo.WriteNextEntry(next_state); + shared_memory.touch_screen_lifo.WriteNextEntry(next_state); } void 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 @@ #pragma once -#include "common/common_funcs.h" -#include "common/common_types.h" +#include <array> + #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" +#include "core/hle/service/hid/controllers/types/touch_types.h" namespace Core::HID { class EmulatedConsole; } // namespace Core::HID namespace Service::HID { +struct TouchScreenSharedMemoryFormat; + class TouchScreen final : public ControllerBase { public: - explicit TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); + explicit TouchScreen(Core::HID::HIDCore& hid_core_, + TouchScreenSharedMemoryFormat& touch_shared_memory); ~TouchScreen() override; // Called when the controller is initialized @@ -31,27 +34,8 @@ public: void SetTouchscreenDimensions(u32 width, u32 height); private: - static constexpr std::size_t MAX_FINGERS = 16; - - // This is nn::hid::TouchScreenState - struct TouchScreenState { - s64 sampling_number{}; - s32 entry_count{}; - INSERT_PADDING_BYTES(4); // Reserved - std::array<Core::HID::TouchState, MAX_FINGERS> states{}; - }; - static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); - - struct TouchSharedMemory { - // This is nn::hid::detail::TouchScreenLifo - Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{}; - static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); - INSERT_PADDING_WORDS(0xF2); - }; - static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size"); - TouchScreenState next_state{}; - TouchSharedMemory* shared_memory = nullptr; + TouchScreenSharedMemoryFormat& shared_memory; Core::HID::EmulatedConsole* console = nullptr; 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "core/hid/hid_types.h" + +namespace Service::HID { + +// This is nn::hid::DebugPadAttribute +struct DebugPadAttribute { + union { + u32 raw{}; + BitField<0, 1, u32> connected; + }; +}; +static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size"); + +// This is nn::hid::DebugPadState +struct DebugPadState { + s64 sampling_number{}; + DebugPadAttribute attribute{}; + Core::HID::DebugPadButton pad_state{}; + Core::HID::AnalogStickState r_stick{}; + Core::HID::AnalogStickState l_stick{}; +}; +static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/point.h" + +namespace Service::HID { +static constexpr size_t MAX_FINGERS = 16; +static constexpr size_t MAX_POINTS = 4; + +// This is nn::hid::GestureType +enum class GestureType : u32 { + Idle, // Nothing touching the screen + Complete, // Set at the end of a touch event + Cancel, // Set when the number of fingers change + Touch, // A finger just touched the screen + Press, // Set if last type is touch and the finger hasn't moved + Tap, // Fast press then release + Pan, // All points moving together across the screen + Swipe, // Fast press movement and release of a single point + Pinch, // All points moving away/closer to the midpoint + Rotate, // All points rotating from the midpoint +}; + +// This is nn::hid::GestureDirection +enum class GestureDirection : u32 { + None, + Left, + Up, + Right, + Down, +}; + +// This is nn::hid::GestureAttribute +struct GestureAttribute { + union { + u32 raw{}; + + BitField<4, 1, u32> is_new_touch; + BitField<8, 1, u32> is_double_tap; + }; +}; +static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); + +// This is nn::hid::GestureState +struct GestureState { + s64 sampling_number{}; + s64 detection_count{}; + GestureType type{GestureType::Idle}; + GestureDirection direction{GestureDirection::None}; + Common::Point<s32> pos{}; + Common::Point<s32> delta{}; + f32 vel_x{}; + f32 vel_y{}; + GestureAttribute attributes{}; + f32 scale{}; + f32 rotation_angle{}; + s32 point_count{}; + std::array<Common::Point<s32>, 4> points{}; +}; +static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); + +struct GestureProperties { + std::array<Common::Point<s32>, MAX_POINTS> points{}; + std::size_t active_points{}; + Common::Point<s32> mid_point{}; + s64 detection_count{}; + u64 delta_time{}; + f32 average_distance{}; + f32 angle{}; +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hid/hid_types.h" + +namespace Service::HID { + +// This is nn::hid::detail::KeyboardState +struct KeyboardState { + s64 sampling_number{}; + Core::HID::KeyboardModifier modifier{}; + Core::HID::KeyboardAttribute attribute{}; + Core::HID::KeyboardKey key{}; +}; +static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/common_types.h" + +namespace 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hid/hid_types.h" + +namespace Service::HID { +static constexpr std::size_t NpadCount = 10; + +// This is nn::hid::NpadJoyHoldType +enum class NpadJoyHoldType : u64 { + Vertical = 0, + Horizontal = 1, +}; + +// This is nn::hid::NpadJoyAssignmentMode +enum class NpadJoyAssignmentMode : u32 { + Dual = 0, + Single = 1, +}; + +// This is nn::hid::NpadJoyDeviceType +enum class NpadJoyDeviceType : s64 { + Left = 0, + Right = 1, +}; + +// This is nn::hid::NpadHandheldActivationMode +enum class NpadHandheldActivationMode : u64 { + Dual = 0, + Single = 1, + None = 2, + MaxActivationMode = 3, +}; + +// This is nn::hid::system::AppletFooterUiAttributesSet +struct AppletFooterUiAttributes { + INSERT_PADDING_BYTES(0x4); +}; + +// This is nn::hid::system::AppletFooterUiType +enum class AppletFooterUiType : u8 { + None = 0, + HandheldNone = 1, + HandheldJoyConLeftOnly = 2, + HandheldJoyConRightOnly = 3, + HandheldJoyConLeftJoyConRight = 4, + JoyDual = 5, + JoyDualLeftOnly = 6, + JoyDualRightOnly = 7, + JoyLeftHorizontal = 8, + JoyLeftVertical = 9, + JoyRightHorizontal = 10, + JoyRightVertical = 11, + SwitchProController = 12, + CompatibleProController = 13, + CompatibleJoyCon = 14, + LarkHvc1 = 15, + LarkHvc2 = 16, + LarkNesLeft = 17, + LarkNesRight = 18, + Lucia = 19, + Verification = 20, + Lagon = 21, +}; + +using AppletFooterUiVariant = u8; + +// This is "nn::hid::system::AppletDetailedUiType". +struct AppletDetailedUiType { + AppletFooterUiVariant ui_variant; + INSERT_PADDING_BYTES(0x2); + AppletFooterUiType footer; +}; +static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size"); +// This is nn::hid::NpadCommunicationMode +enum class NpadCommunicationMode : u64 { + Mode_5ms = 0, + Mode_10ms = 1, + Mode_15ms = 2, + Default = 3, +}; + +enum class NpadRevision : u32 { + Revision0 = 0, + Revision1 = 1, + Revision2 = 2, + Revision3 = 3, +}; + +// This is nn::hid::detail::ColorAttribute +enum class ColorAttribute : u32 { + Ok = 0, + ReadError = 1, + NoController = 2, +}; +static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size"); + +// This is nn::hid::detail::NpadFullKeyColorState +struct NpadFullKeyColorState { + ColorAttribute attribute{ColorAttribute::NoController}; + Core::HID::NpadControllerColor fullkey{}; +}; +static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size"); + +// This is nn::hid::detail::NpadJoyColorState +struct NpadJoyColorState { + ColorAttribute attribute{ColorAttribute::NoController}; + Core::HID::NpadControllerColor left{}; + Core::HID::NpadControllerColor right{}; +}; +static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size"); + +// This is nn::hid::NpadAttribute +struct NpadAttribute { + union { + u32 raw{}; + BitField<0, 1, u32> is_connected; + BitField<1, 1, u32> is_wired; + BitField<2, 1, u32> is_left_connected; + BitField<3, 1, u32> is_left_wired; + BitField<4, 1, u32> is_right_connected; + BitField<5, 1, u32> is_right_wired; + }; +}; +static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size"); + +// This is nn::hid::NpadFullKeyState +// This is nn::hid::NpadHandheldState +// This is nn::hid::NpadJoyDualState +// This is nn::hid::NpadJoyLeftState +// This is nn::hid::NpadJoyRightState +// This is nn::hid::NpadPalmaState +// This is nn::hid::NpadSystemExtState +struct NPadGenericState { + s64_le sampling_number{}; + Core::HID::NpadButtonState npad_buttons{}; + Core::HID::AnalogStickState l_stick{}; + Core::HID::AnalogStickState r_stick{}; + NpadAttribute connection_status{}; + INSERT_PADDING_BYTES(4); // Reserved +}; +static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); + +// This is nn::hid::server::NpadGcTriggerState +struct NpadGcTriggerState { + s64 sampling_number{}; + s32 l_analog{}; + s32 r_analog{}; +}; +static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); + +// This is nn::hid::NpadSystemProperties +struct NPadSystemProperties { + union { + s64 raw{}; + BitField<0, 1, s64> is_charging_joy_dual; + BitField<1, 1, s64> is_charging_joy_left; + BitField<2, 1, s64> is_charging_joy_right; + BitField<3, 1, s64> is_powered_joy_dual; + BitField<4, 1, s64> is_powered_joy_left; + BitField<5, 1, s64> is_powered_joy_right; + BitField<9, 1, s64> is_system_unsupported_button; + BitField<10, 1, s64> is_system_ext_unsupported_button; + BitField<11, 1, s64> is_vertical; + BitField<12, 1, s64> is_horizontal; + BitField<13, 1, s64> use_plus; + BitField<14, 1, s64> use_minus; + BitField<15, 1, s64> use_directional_buttons; + }; +}; +static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); + +// This is nn::hid::NpadSystemButtonProperties +struct NpadSystemButtonProperties { + union { + s32 raw{}; + BitField<0, 1, s32> is_home_button_protection_enabled; + }; +}; +static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size"); + +// This is nn::hid::system::DeviceType +struct DeviceType { + union { + u32 raw{}; + BitField<0, 1, s32> fullkey; + BitField<1, 1, s32> debug_pad; + BitField<2, 1, s32> handheld_left; + BitField<3, 1, s32> handheld_right; + BitField<4, 1, s32> joycon_left; + BitField<5, 1, s32> joycon_right; + BitField<6, 1, s32> palma; + BitField<7, 1, s32> lark_hvc_left; + BitField<8, 1, s32> lark_hvc_right; + BitField<9, 1, s32> lark_nes_left; + BitField<10, 1, s32> lark_nes_right; + BitField<11, 1, s32> handheld_lark_hvc_left; + BitField<12, 1, s32> handheld_lark_hvc_right; + BitField<13, 1, s32> handheld_lark_nes_left; + BitField<14, 1, s32> handheld_lark_nes_right; + BitField<15, 1, s32> lucia; + BitField<16, 1, s32> lagon; + BitField<17, 1, s32> lager; + BitField<31, 1, s32> system; + }; +}; + +// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl +struct NfcXcdDeviceHandleStateImpl { + u64 handle{}; + bool is_available{}; + bool is_activated{}; + INSERT_PADDING_BYTES(0x6); // Reserved + u64 sampling_number{}; +}; +static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, + "NfcXcdDeviceHandleStateImpl is an invalid size"); + +// This is nn::hid::NpadLarkType +enum class NpadLarkType : u32 { + Invalid, + H1, + H2, + NL, + NR, +}; + +// This is nn::hid::NpadLuciaType +enum class NpadLuciaType : u32 { + Invalid, + J, + E, + U, +}; + +// This is nn::hid::NpadLagonType +enum class NpadLagonType : u32 { + Invalid, +}; + +// This is nn::hid::NpadLagerType +enum class NpadLagerType : u32 { + Invalid, + J, + E, + U, +}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <array> + +#include <array> +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/point.h" +#include "core/hid/hid_types.h" + +namespace Service::HID { +static constexpr std::size_t MAX_FINGERS = 16; +static constexpr size_t MAX_POINTS = 4; + +// This is nn::hid::GestureType +enum class GestureType : u32 { + Idle, // Nothing touching the screen + Complete, // Set at the end of a touch event + Cancel, // Set when the number of fingers change + Touch, // A finger just touched the screen + Press, // Set if last type is touch and the finger hasn't moved + Tap, // Fast press then release + Pan, // All points moving together across the screen + Swipe, // Fast press movement and release of a single point + Pinch, // All points moving away/closer to the midpoint + Rotate, // All points rotating from the midpoint +}; + +// This is nn::hid::GestureDirection +enum class GestureDirection : u32 { + None, + Left, + Up, + Right, + Down, +}; + +// This is nn::hid::GestureAttribute +struct GestureAttribute { + union { + u32 raw{}; + + BitField<4, 1, u32> is_new_touch; + BitField<8, 1, u32> is_double_tap; + }; +}; +static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); + +// This is nn::hid::GestureState +struct GestureState { + s64 sampling_number{}; + s64 detection_count{}; + GestureType type{GestureType::Idle}; + GestureDirection direction{GestureDirection::None}; + Common::Point<s32> pos{}; + Common::Point<s32> delta{}; + f32 vel_x{}; + f32 vel_y{}; + GestureAttribute attributes{}; + f32 scale{}; + f32 rotation_angle{}; + s32 point_count{}; + std::array<Common::Point<s32>, 4> points{}; +}; +static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); + +struct GestureProperties { + std::array<Common::Point<s32>, MAX_POINTS> points{}; + std::size_t active_points{}; + Common::Point<s32> mid_point{}; + s64 detection_count{}; + u64 delta_time{}; + f32 average_distance{}; + f32 angle{}; +}; + +// This is nn::hid::TouchScreenState +struct TouchScreenState { + s64 sampling_number{}; + s32 entry_count{}; + INSERT_PADDING_BYTES(4); // Reserved + std::array<Core::HID::TouchState, MAX_FINGERS> states{}; +}; +static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); + +} // 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 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include <cstring> -#include "common/common_types.h" -#include "core/core_timing.h" -#include "core/hid/hid_core.h" -#include "core/hle/service/hid/controllers/xpad.h" - -namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; - -XPad::XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} { - static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size, - "XpadSharedMemory is bigger than the shared memory"); - shared_memory = std::construct_at( - reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET)); -} -XPad::~XPad() = default; - -void XPad::OnInit() {} - -void XPad::OnRelease() {} - -void XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - if (!IsControllerActivated()) { - shared_memory->basic_xpad_lifo.buffer_count = 0; - shared_memory->basic_xpad_lifo.buffer_tail = 0; - return; - } - - const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; - // TODO(ogniK): Update xpad states - - shared_memory->basic_xpad_lifo.WriteNextEntry(next_state); -} - -} // 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 @@ -// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/bit_field.h" -#include "common/common_types.h" -#include "core/hid/hid_types.h" -#include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Service::HID { -class XPad final : public ControllerBase { -public: - explicit XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); - ~XPad() override; - - // Called when the controller is initialized - void OnInit() override; - - // When the controller is released - void OnRelease() override; - - // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; - -private: - // This is nn::hid::BasicXpadAttributeSet - struct BasicXpadAttributeSet { - union { - u32 raw{}; - BitField<0, 1, u32> is_connected; - BitField<1, 1, u32> is_wired; - BitField<2, 1, u32> is_left_connected; - BitField<3, 1, u32> is_left_wired; - BitField<4, 1, u32> is_right_connected; - BitField<5, 1, u32> is_right_wired; - }; - }; - static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size"); - - // This is nn::hid::BasicXpadButtonSet - struct BasicXpadButtonSet { - union { - u32 raw{}; - // Button states - BitField<0, 1, u32> a; - BitField<1, 1, u32> b; - BitField<2, 1, u32> x; - BitField<3, 1, u32> y; - BitField<4, 1, u32> l_stick; - BitField<5, 1, u32> r_stick; - BitField<6, 1, u32> l; - BitField<7, 1, u32> r; - BitField<8, 1, u32> zl; - BitField<9, 1, u32> zr; - BitField<10, 1, u32> plus; - BitField<11, 1, u32> minus; - - // D-Pad - BitField<12, 1, u32> d_left; - BitField<13, 1, u32> d_up; - BitField<14, 1, u32> d_right; - BitField<15, 1, u32> d_down; - - // Left JoyStick - BitField<16, 1, u32> l_stick_left; - BitField<17, 1, u32> l_stick_up; - BitField<18, 1, u32> l_stick_right; - BitField<19, 1, u32> l_stick_down; - - // Right JoyStick - BitField<20, 1, u32> r_stick_left; - BitField<21, 1, u32> r_stick_up; - BitField<22, 1, u32> r_stick_right; - BitField<23, 1, u32> r_stick_down; - - // Not always active? - BitField<24, 1, u32> left_sl; - BitField<25, 1, u32> left_sr; - - BitField<26, 1, u32> right_sl; - BitField<27, 1, u32> right_sr; - - BitField<28, 1, u32> palma; - BitField<30, 1, u32> handheld_left_b; - }; - }; - static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size"); - - // This is nn::hid::detail::BasicXpadState - struct BasicXpadState { - s64 sampling_number{}; - BasicXpadAttributeSet attributes{}; - BasicXpadButtonSet pad_states{}; - Core::HID::AnalogStickState l_stick{}; - Core::HID::AnalogStickState r_stick{}; - }; - static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); - - struct XpadSharedMemory { - // This is nn::hid::detail::BasicXpadLifo - Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{}; - static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); - INSERT_PADDING_WORDS(0x4E); - }; - static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size"); - - BasicXpadState next_state{}; - XpadSharedMemory* shared_memory = nullptr; -}; -} // 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}; constexpr Result InvalidNpadId{ErrorModule::HID, 709}; constexpr Result NpadNotConnected{ErrorModule::HID, 710}; constexpr Result InvalidArraySize{ErrorModule::HID, 715}; + +constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041}; +constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042}; +constexpr Result ResultSharedMemoryNotInitialized{ErrorModule::HID, 1043}; +constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044}; +constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046}; +constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047}; + constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302}; } // 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/hle/kernel/k_process.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid_debug_server.h" #include "core/hle/service/hid/hid_firmware_settings.h" @@ -20,6 +22,12 @@ void LoopProcess(Core::System& system) { std::shared_ptr<HidFirmwareSettings> firmware_settings = std::make_shared<HidFirmwareSettings>(); + // TODO: Remove this hack until this service is emulated properly. + const auto process_list = system.Kernel().GetProcessList(); + if (!process_list.empty()) { + resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); + } + server_manager->RegisterNamedService( "hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings)); 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 @@ #include "core/hle/service/hid/controllers/seven_six_axis.h" #include "core/hle/service/hid/controllers/six_axis.h" #include "core/hle/service/hid/controllers/touchscreen.h" +#include "core/hle/service/hid/controllers/types/npad_types.h" namespace Service::HID { @@ -222,11 +223,14 @@ void IHidServer::CreateAppletResource(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + Result result = GetResourceManager()->CreateAppletResource(applet_resource_user_id); + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", + applet_resource_user_id, result.raw); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - rb.Push(ResultSuccess); - rb.PushIpcInterface<IAppletResource>(system, resource_manager); + rb.Push(result); + rb.PushIpcInterface<IAppletResource>(system, resource_manager, applet_resource_user_id); } void IHidServer::ActivateDebugPad(HLERequestContext& ctx) { @@ -1096,7 +1100,7 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) { void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - NPad::NpadRevision revision; + NpadRevision revision; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -1119,7 +1123,7 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto hold_type{rp.PopEnum<NPad::NpadJoyHoldType>()}; + const auto hold_type{rp.PopEnum<NpadJoyHoldType>()}; GetResourceManager()->GetNpad()->SetHoldType(hold_type); @@ -1154,8 +1158,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx) Core::HID::NpadIdType new_npad_id{}; auto controller = GetResourceManager()->GetNpad(); - controller->SetNpadMode(new_npad_id, parameters.npad_id, NPad::NpadJoyDeviceType::Left, - NPad::NpadJoyAssignmentMode::Single); + controller->SetNpadMode(new_npad_id, parameters.npad_id, NpadJoyDeviceType::Left, + NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1170,7 +1174,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) { Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - NPad::NpadJoyDeviceType npad_joy_device_type; + NpadJoyDeviceType npad_joy_device_type; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); @@ -1179,7 +1183,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) { Core::HID::NpadIdType new_npad_id{}; auto controller = GetResourceManager()->GetNpad(); controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, - NPad::NpadJoyAssignmentMode::Single); + NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", parameters.npad_id, parameters.applet_resource_user_id, @@ -1202,7 +1206,7 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) { Core::HID::NpadIdType new_npad_id{}; auto controller = GetResourceManager()->GetNpad(); - controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NPad::NpadJoyAssignmentMode::Dual); + controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NpadJoyAssignmentMode::Dual); LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); // Spams a lot when controller applet is open @@ -1254,7 +1258,7 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) { void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto activation_mode{rp.PopEnum<NPad::NpadHandheldActivationMode>()}; + const auto activation_mode{rp.PopEnum<NpadHandheldActivationMode>()}; GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode); @@ -1346,7 +1350,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext Core::HID::NpadIdType npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; - NPad::NpadJoyDeviceType npad_joy_device_type; + NpadJoyDeviceType npad_joy_device_type; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); @@ -1356,7 +1360,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext auto controller = GetResourceManager()->GetNpad(); const auto is_reassigned = controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type, - NPad::NpadJoyAssignmentMode::Single); + NpadJoyAssignmentMode::Single); LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", parameters.npad_id, parameters.applet_resource_user_id, @@ -2312,7 +2316,7 @@ void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) { void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; - const auto communication_mode{rp.PopEnum<NPad::NpadCommunicationMode>()}; + const auto communication_mode{rp.PopEnum<NpadCommunicationMode>()}; GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode); 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 @@ #include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/controllers/palma.h" #include "core/hle/service/hid/controllers/touchscreen.h" +#include "core/hle/service/hid/controllers/types/npad_types.h" #include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/hid_system_server.h" #include "core/hle/service/hid/resource_manager.h" @@ -63,13 +65,13 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour {329, nullptr, "DetachAbstractedPadAll"}, {330, nullptr, "CheckAbstractedPadConnection"}, {500, nullptr, "SetAppletResourceUserId"}, - {501, nullptr, "RegisterAppletResourceUserId"}, - {502, nullptr, "UnregisterAppletResourceUserId"}, - {503, nullptr, "EnableAppletToGetInput"}, + {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"}, + {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"}, + {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"}, {504, nullptr, "SetAruidValidForVibration"}, - {505, nullptr, "EnableAppletToGetSixAxisSensor"}, - {506, nullptr, "EnableAppletToGetPadInput"}, - {507, nullptr, "EnableAppletToGetTouchScreen"}, + {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"}, + {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"}, + {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"}, {510, nullptr, "SetVibrationMasterVolume"}, {511, nullptr, "GetVibrationMasterVolume"}, {512, nullptr, "BeginPermitVibrationSession"}, @@ -327,7 +329,7 @@ void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) { LOG_DEBUG(Service_HID, "called, npad_id_type={}", npad_id_type); // Spams a lot when controller applet is running - const NPad::AppletDetailedUiType detailed_ui_type = + const AppletDetailedUiType detailed_ui_type = GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type); IPC::ResponseBuilder rb{ctx, 3}; @@ -420,6 +422,129 @@ void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } +void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + bool enable_input; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_INFO(Service_HID, "called, enable_input={}, applet_resource_user_id={}", + parameters.enable_input, parameters.applet_resource_user_id); + + Result result = GetResourceManager()->RegisterAppletResourceUserId( + parameters.applet_resource_user_id, parameters.enable_input); + + if (result.IsSuccess()) { + // result = GetResourceManager()->GetNpad()->RegisterAppletResourceUserId( + // parameters.applet_resource_user_id); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::UnregisterAppletResourceUserId(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + u64 applet_resource_user_id{rp.Pop<u64>()}; + + LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); + + GetResourceManager()->UnregisterAppletResourceUserId(applet_resource_user_id); + // GetResourceManager()->GetNpad()->UnregisterAppletResourceUserId(applet_resource_user_id); + // GetResourceManager()->GetPalma()->UnregisterAppletResourceUserId(applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::EnableAppletToGetInput(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + bool is_enabled; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", + parameters.is_enabled, parameters.applet_resource_user_id); + + GetResourceManager()->EnableInput(parameters.applet_resource_user_id, parameters.is_enabled); + // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + bool is_enabled; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", + parameters.is_enabled, parameters.applet_resource_user_id); + + GetResourceManager()->EnableTouchScreen(parameters.applet_resource_user_id, + parameters.is_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::EnableAppletToGetPadInput(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + bool is_enabled; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", + parameters.is_enabled, parameters.applet_resource_user_id); + + GetResourceManager()->EnablePadInput(parameters.applet_resource_user_id, parameters.is_enabled); + // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + bool is_enabled; + INSERT_PADDING_WORDS_NOINIT(1); + u64 applet_resource_user_id; + }; + static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}", + parameters.is_enabled, parameters.applet_resource_user_id); + + GetResourceManager()->EnableTouchScreen(parameters.applet_resource_user_id, + parameters.is_enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) { 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: void HasLeftRightBattery(HLERequestContext& ctx); void GetUniquePadsFromNpad(HLERequestContext& ctx); void GetIrSensorState(HLERequestContext& ctx); + void RegisterAppletResourceUserId(HLERequestContext& ctx); + void UnregisterAppletResourceUserId(HLERequestContext& ctx); + void EnableAppletToGetInput(HLERequestContext& ctx); + void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx); + void EnableAppletToGetPadInput(HLERequestContext& ctx); + void EnableAppletToGetTouchScreen(HLERequestContext& ctx); void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx); void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx); 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 @@ #include "core/hle/service/hid/resource_manager.h" #include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/hid/controllers/applet_resource.h" #include "core/hle/service/hid/controllers/console_six_axis.h" #include "core/hle/service/hid/controllers/debug_pad.h" #include "core/hle/service/hid/controllers/gesture.h" @@ -17,10 +18,10 @@ #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/palma.h" #include "core/hle/service/hid/controllers/seven_six_axis.h" +#include "core/hle/service/hid/controllers/shared_memory_format.h" #include "core/hle/service/hid/controllers/six_axis.h" #include "core/hle/service/hid/controllers/stubbed.h" #include "core/hle/service/hid/controllers/touchscreen.h" -#include "core/hle/service/hid/controllers/xpad.h" namespace Service::HID { @@ -33,7 +34,9 @@ constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 10 constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) ResourceManager::ResourceManager(Core::System& system_) - : system{system_}, service_context{system_, "hid"} {} + : system{system_}, service_context{system_, "hid"} { + applet_resource = std::make_shared<AppletResource>(system); +} ResourceManager::~ResourceManager() = default; @@ -42,41 +45,49 @@ void ResourceManager::Initialize() { return; } - u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer(); - debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory); - mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory); - debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory); - keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory); - unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory); - npad = std::make_shared<NPad>(system.HIDCore(), shared_memory, service_context); - gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory); - touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory); - xpad = std::make_shared<XPad>(system.HIDCore(), shared_memory); + system.HIDCore().ReloadInputDevices(); + is_initialized = true; +} + +void ResourceManager::InitializeController(u64 aruid) { + SharedMemoryFormat* shared_memory = nullptr; + const auto result = applet_resource->GetSharedMemoryFormat(&shared_memory, aruid); + if (result.IsError()) { + return; + } + + debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory->debug_pad); + mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory->mouse); + debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory->debug_mouse); + keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory->keyboard); + unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory->unique_pad.header); + npad = std::make_shared<NPad>(system.HIDCore(), shared_memory->npad, service_context); + gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory->gesture); + touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory->touch_screen); - palma = std::make_shared<Palma>(system.HIDCore(), shared_memory, service_context); + palma = std::make_shared<Palma>(system.HIDCore(), service_context); - home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory); - sleep_button = std::make_shared<SleepButton>(system.HIDCore(), shared_memory); - capture_button = std::make_shared<CaptureButton>(system.HIDCore(), shared_memory); + home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory->home_button.header); + sleep_button = + std::make_shared<SleepButton>(system.HIDCore(), shared_memory->sleep_button.header); + capture_button = + std::make_shared<CaptureButton>(system.HIDCore(), shared_memory->capture_button.header); + digitizer = std::make_shared<Digitizer>(system.HIDCore(), shared_memory->digitizer.header); six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad); - console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory); + console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory->console); seven_six_axis = std::make_shared<SevenSixAxis>(system); - home_button->SetCommonHeaderOffset(0x4C00); - sleep_button->SetCommonHeaderOffset(0x4E00); - capture_button->SetCommonHeaderOffset(0x5000); - unique_pad->SetCommonHeaderOffset(0x5A00); - debug_mouse->SetCommonHeaderOffset(0x3DC00); - // Homebrew doesn't try to activate some controllers, so we activate them by default npad->Activate(); six_axis->Activate(); touch_screen->Activate(); +} - system.HIDCore().ReloadInputDevices(); - is_initialized = true; +std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const { + return applet_resource; } + std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const { return capture_button; } @@ -93,6 +104,10 @@ std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const { return debug_pad; } +std::shared_ptr<Digitizer> ResourceManager::GetDigitizer() const { + return digitizer; +} + std::shared_ptr<Gesture> ResourceManager::GetGesture() const { return gesture; } @@ -137,10 +152,86 @@ std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const { return unique_pad; } +Result ResourceManager::CreateAppletResource(u64 aruid) { + if (aruid == 0) { + const auto result = RegisterCoreAppletResource(); + if (result.IsError()) { + return result; + } + return GetNpad()->Activate(); + } + + const auto result = CreateAppletResourceImpl(aruid); + if (result.IsError()) { + return result; + } + return GetNpad()->Activate(aruid); +} + +Result ResourceManager::CreateAppletResourceImpl(u64 aruid) { + std::scoped_lock lock{shared_mutex}; + const auto result = applet_resource->CreateAppletResource(aruid); + if (result.IsSuccess()) { + InitializeController(aruid); + } + return result; +} + +Result ResourceManager::RegisterCoreAppletResource() { + std::scoped_lock lock{shared_mutex}; + return applet_resource->RegisterCoreAppletResource(); +} + +Result ResourceManager::UnregisterCoreAppletResource() { + std::scoped_lock lock{shared_mutex}; + return applet_resource->UnregisterCoreAppletResource(); +} + +Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) { + std::scoped_lock lock{shared_mutex}; + return applet_resource->RegisterAppletResourceUserId(aruid, bool_value); +} + +void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { + std::scoped_lock lock{shared_mutex}; + applet_resource->UnregisterAppletResourceUserId(aruid); +} + +Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { + std::scoped_lock lock{shared_mutex}; + return applet_resource->GetSharedMemoryHandle(out_handle, aruid); +} + +void ResourceManager::FreeAppletResourceId(u64 aruid) { + std::scoped_lock lock{shared_mutex}; + applet_resource->FreeAppletResourceId(aruid); +} + +void ResourceManager::EnableInput(u64 aruid, bool is_enabled) { + std::scoped_lock lock{shared_mutex}; + applet_resource->EnableInput(aruid, is_enabled); +} + +void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) { + std::scoped_lock lock{shared_mutex}; + applet_resource->EnableSixAxisSensor(aruid, is_enabled); +} + +void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) { + std::scoped_lock lock{shared_mutex}; + applet_resource->EnablePadInput(aruid, is_enabled); +} + +void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) { + std::scoped_lock lock{shared_mutex}; + applet_resource->EnableTouchScreen(aruid, is_enabled); +} + void ResourceManager::UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); debug_pad->OnUpdate(core_timing); + digitizer->OnUpdate(core_timing); unique_pad->OnUpdate(core_timing); gesture->OnUpdate(core_timing); touch_screen->OnUpdate(core_timing); @@ -148,7 +239,6 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data, home_button->OnUpdate(core_timing); sleep_button->OnUpdate(core_timing); capture_button->OnUpdate(core_timing); - xpad->OnUpdate(core_timing); } void 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 console_six_axis->OnUpdate(core_timing); } -IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource) - : ServiceFramework{system_, "IAppletResource"} { +IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource, + u64 applet_resource_user_id) + : ServiceFramework{system_, "IAppletResource"}, aruid{applet_resource_user_id}, + resource_manager{resource} { static const FunctionInfo functions[] = { {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, }; RegisterHandlers(functions); - resource->Initialize(); - // Register update callbacks npad_update_event = Core::Timing::CreateEvent( "HID::UpdatePadCallback", @@ -228,14 +318,18 @@ IAppletResource::~IAppletResource() { system.CoreTiming().UnscheduleEvent(default_update_event, 0); system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); + resource_manager->FreeAppletResourceId(aruid); } void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) { - LOG_DEBUG(Service_HID, "called"); + Kernel::KSharedMemory* handle; + const auto result = resource_manager->GetSharedMemoryHandle(&handle, aruid); + + LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw); IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(&system.Kernel().GetHidSharedMem()); + rb.Push(result); + rb.PushCopyObjects(handle); } } // 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 @@ #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/service.h" +namespace Core { +class System; +} + namespace Core::Timing { struct EventType; } +namespace Kernel { +class KSharedMemory; +} + namespace Service::HID { +class AppletResource; class Controller_Stubbed; class ConsoleSixAxis; class DebugPad; @@ -22,10 +31,10 @@ class Palma; class SevenSixAxis; class SixAxis; class TouchScreen; -class XPad; using CaptureButton = Controller_Stubbed; -using DebugMouse = Controller_Stubbed; +using DebugMouse = Mouse; +using Digitizer = Controller_Stubbed; using HomeButton = Controller_Stubbed; using SleepButton = Controller_Stubbed; using UniquePad = Controller_Stubbed; @@ -37,11 +46,14 @@ public: ~ResourceManager(); void Initialize(); + void InitializeController(u64 aruid); + std::shared_ptr<AppletResource> GetAppletResource() const; std::shared_ptr<CaptureButton> GetCaptureButton() const; std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const; std::shared_ptr<DebugMouse> GetDebugMouse() const; std::shared_ptr<DebugPad> GetDebugPad() const; + std::shared_ptr<Digitizer> GetDigitizer() const; std::shared_ptr<Gesture> GetGesture() const; std::shared_ptr<HomeButton> GetHomeButton() const; std::shared_ptr<Keyboard> GetKeyboard() const; @@ -54,18 +66,39 @@ public: std::shared_ptr<TouchScreen> GetTouchScreen() const; std::shared_ptr<UniquePad> GetUniquePad() const; + Result CreateAppletResource(u64 aruid); + + Result RegisterCoreAppletResource(); + Result UnregisterCoreAppletResource(); + Result RegisterAppletResourceUserId(u64 aruid, bool bool_value); + void UnregisterAppletResourceUserId(u64 aruid); + + Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); + void FreeAppletResourceId(u64 aruid); + + void EnableInput(u64 aruid, bool is_enabled); + void EnableSixAxisSensor(u64 aruid, bool is_enabled); + void EnablePadInput(u64 aruid, bool is_enabled); + void EnableTouchScreen(u64 aruid, bool is_enabled); + void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); private: + Result CreateAppletResourceImpl(u64 aruid); + bool is_initialized{false}; + mutable std::mutex shared_mutex; + std::shared_ptr<AppletResource> applet_resource = nullptr; + std::shared_ptr<CaptureButton> capture_button = nullptr; std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr; std::shared_ptr<DebugMouse> debug_mouse = nullptr; std::shared_ptr<DebugPad> debug_pad = nullptr; + std::shared_ptr<Digitizer> digitizer = nullptr; std::shared_ptr<Gesture> gesture = nullptr; std::shared_ptr<HomeButton> home_button = nullptr; std::shared_ptr<Keyboard> keyboard = nullptr; @@ -77,7 +110,6 @@ private: std::shared_ptr<SleepButton> sleep_button = nullptr; std::shared_ptr<TouchScreen> touch_screen = nullptr; std::shared_ptr<UniquePad> unique_pad = nullptr; - std::shared_ptr<XPad> xpad = nullptr; // TODO: Create these resources // std::shared_ptr<AudioControl> audio_control = nullptr; @@ -96,7 +128,8 @@ private: class IAppletResource final : public ServiceFramework<IAppletResource> { public: - explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource); + explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource, + u64 applet_resource_user_id); ~IAppletResource() override; private: @@ -106,6 +139,9 @@ private: std::shared_ptr<Core::Timing::EventType> default_update_event; std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; std::shared_ptr<Core::Timing::EventType> motion_update_event; + + u64 aruid; + std::shared_ptr<ResourceManager> resource_manager; }; } // 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:: HLERequestContext::~HLERequestContext() = default; -void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_table, - u32_le* src_cmdbuf, bool incoming) { +void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, + bool incoming) { + client_handle_table = &process.GetHandleTable(); + IPC::RequestParser rp(src_cmdbuf); command_header = rp.PopRaw<IPC::CommandHeader>(); @@ -160,7 +162,8 @@ void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_ta if (command_header->enable_handle_descriptor) { handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); if (handle_descriptor_header->send_current_pid) { - pid = rp.Pop<u64>(); + pid = process.GetProcessId(); + rp.Skip(2, false); } if (incoming) { // Populate the object lists with the data in the IPC request. @@ -267,9 +270,9 @@ void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_ta rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. } -Result HLERequestContext::PopulateFromIncomingCommandBuffer( - const Kernel::KHandleTable& handle_table, u32_le* src_cmdbuf) { - ParseCommandBuffer(handle_table, src_cmdbuf, true); +Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, + u32_le* src_cmdbuf) { + ParseCommandBuffer(process, src_cmdbuf, true); if (command_header->IsCloseCommand()) { // 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 { class KAutoObject; class KernelCore; class KHandleTable; +class KProcess; class KServerSession; class KThread; } // namespace Kernel @@ -75,6 +76,7 @@ protected: using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>; using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; +using SessionRequestHandlerFactory = std::function<SessionRequestHandlerPtr()>; /** * Manages the underlying HLE requests for a session, and whether (or not) the session should be @@ -194,8 +196,7 @@ public: } /// Populates this context with data from the requesting process/thread. - Result PopulateFromIncomingCommandBuffer(const Kernel::KHandleTable& handle_table, - u32_le* src_cmdbuf); + Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf); /// Writes data from this context back to the requesting process/thread. Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread); @@ -358,6 +359,10 @@ public: return *thread; } + Kernel::KHandleTable& GetClientHandleTable() { + return *client_handle_table; + } + [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { return manager.lock(); } @@ -373,12 +378,12 @@ public: private: friend class IPC::ResponseBuilder; - void ParseCommandBuffer(const Kernel::KHandleTable& handle_table, u32_le* src_cmdbuf, - bool incoming); + void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming); std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; Kernel::KServerSession* server_session{}; - Kernel::KThread* thread; + Kernel::KHandleTable* client_handle_table{}; + Kernel::KThread* thread{}; std::vector<Handle> incoming_move_handles; 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 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "core/arm/debug.h" #include "core/arm/symbols.h" #include "core/core.h" #include "core/hle/kernel/k_code_memory.h" @@ -98,8 +99,9 @@ public: if (return_value == 0) { // The callback has written to the output executable code range, // requiring an instruction cache invalidation - system.InvalidateCpuInstructionCacheRange(configuration.user_rx_memory.offset, - configuration.user_rx_memory.size); + Core::InvalidateInstructionCacheRange(process.GetPointerUnsafe(), + configuration.user_rx_memory.offset, + configuration.user_rx_memory.size); // Write back to the IPC output buffer, if provided 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 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <memory> -#include <fmt/format.h> -#include <mbedtls/sha256.h> - -#include "common/alignment.h" -#include "common/hex_util.h" -#include "common/scope_exit.h" -#include "core/core.h" -#include "core/hle/kernel/k_page_table.h" -#include "core/hle/kernel/svc_results.h" -#include "core/hle/kernel/svc_types.h" -#include "core/hle/service/ipc_helpers.h" #include "core/hle/service/ldr/ldr.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/service.h" -#include "core/loader/nro.h" -#include "core/memory.h" namespace Service::LDR { -constexpr Result ERROR_INSUFFICIENT_ADDRESS_SPACE{ErrorModule::RO, 2}; - -[[maybe_unused]] constexpr Result ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51}; -constexpr Result ERROR_INVALID_NRO{ErrorModule::Loader, 52}; -constexpr Result ERROR_INVALID_NRR{ErrorModule::Loader, 53}; -constexpr Result ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54}; -constexpr Result ERROR_MAXIMUM_NRO{ErrorModule::Loader, 55}; -constexpr Result ERROR_MAXIMUM_NRR{ErrorModule::Loader, 56}; -constexpr Result ERROR_ALREADY_LOADED{ErrorModule::Loader, 57}; -constexpr Result ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81}; -constexpr Result ERROR_INVALID_SIZE{ErrorModule::Loader, 82}; -constexpr Result ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84}; -[[maybe_unused]] constexpr Result ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85}; -constexpr Result ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87}; - -constexpr std::size_t MAXIMUM_LOADED_RO{0x40}; -constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200}; - -constexpr std::size_t TEXT_INDEX{0}; -constexpr std::size_t RO_INDEX{1}; -constexpr std::size_t DATA_INDEX{2}; - -struct NRRCertification { - u64_le application_id_mask; - u64_le application_id_pattern; - INSERT_PADDING_BYTES(0x10); - std::array<u8, 0x100> public_key; // Also known as modulus - std::array<u8, 0x100> signature; -}; -static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid size."); - -struct NRRHeader { - u32_le magic; - u32_le certification_signature_key_generation; // 9.0.0+ - INSERT_PADDING_WORDS(2); - NRRCertification certification; - std::array<u8, 0x100> signature; - u64_le application_id; - u32_le size; - u8 nrr_kind; // 7.0.0+ - INSERT_PADDING_BYTES(3); - u32_le hash_offset; - u32_le hash_count; - INSERT_PADDING_WORDS(2); -}; -static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size."); - -struct SegmentHeader { - u32_le memory_offset; - u32_le memory_size; -}; -static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size."); - -struct NROHeader { - // Switchbrew calls this "Start" (0x10) - INSERT_PADDING_WORDS(1); - u32_le mod_offset; - INSERT_PADDING_WORDS(2); - - // Switchbrew calls this "Header" (0x70) - u32_le magic; - u32_le version; - u32_le nro_size; - u32_le flags; - // .text, .ro, .data - std::array<SegmentHeader, 3> segment_headers; - u32_le bss_size; - INSERT_PADDING_WORDS(1); - std::array<u8, 0x20> build_id; - u32_le dso_handle_offset; - INSERT_PADDING_WORDS(1); - // .apiInfo, .dynstr, .dynsym - std::array<SegmentHeader, 3> segment_headers_2; -}; -static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size."); - -using SHA256Hash = std::array<u8, 0x20>; - -struct NROInfo { - SHA256Hash hash{}; - VAddr nro_address{}; - std::size_t nro_size{}; - VAddr bss_address{}; - std::size_t bss_size{}; - std::size_t text_size{}; - std::size_t ro_size{}; - std::size_t data_size{}; - VAddr src_addr{}; -}; -static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size."); - class DebugMonitor final : public ServiceFramework<DebugMonitor> { public: explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} { @@ -158,541 +53,12 @@ public: } }; -class RelocatableObject final : public ServiceFramework<RelocatableObject> { -public: - explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &RelocatableObject::LoadModule, "LoadModule"}, - {1, &RelocatableObject::UnloadModule, "UnloadModule"}, - {2, &RelocatableObject::RegisterModuleInfo, "RegisterModuleInfo"}, - {3, &RelocatableObject::UnregisterModuleInfo, "UnregisterModuleInfo"}, - {4, &RelocatableObject::Initialize, "Initialize"}, - {10, nullptr, "RegisterModuleInfo2"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - - void RegisterModuleInfo(HLERequestContext& ctx) { - struct Parameters { - u64_le process_id; - u64_le nrr_address; - u64_le nrr_size; - }; - - IPC::RequestParser rp{ctx}; - const auto [process_id, nrr_address, nrr_size] = rp.PopRaw<Parameters>(); - - LOG_DEBUG(Service_LDR, - "called with process_id={:016X}, nrr_address={:016X}, nrr_size={:016X}", - process_id, nrr_address, nrr_size); - - if (!initialized) { - LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NOT_INITIALIZED); - return; - } - - if (nrr.size() >= MAXIMUM_LOADED_RO) { - LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs " - "(0x40)! Failing..."); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_MAXIMUM_NRR); - return; - } - - // NRR Address does not fall on 0x1000 byte boundary - if (!Common::Is4KBAligned(nrr_address)) { - LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", - nrr_address); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ALIGNMENT); - return; - } - - // NRR Size is zero or causes overflow - if (nrr_address + nrr_size <= nrr_address || nrr_size == 0 || - !Common::Is4KBAligned(nrr_size)) { - LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})", - nrr_address, nrr_size); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_SIZE); - return; - } - - // Read NRR data from memory - std::vector<u8> nrr_data(nrr_size); - system.ApplicationMemory().ReadBlock(nrr_address, nrr_data.data(), nrr_size); - NRRHeader header; - std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader)); - - if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) { - LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_NRR); - return; - } - - if (header.size != nrr_size) { - LOG_ERROR(Service_LDR, - "NRR header reported size did not match LoadNrr parameter size! " - "(header_size={:016X}, loadnrr_size={:016X})", - header.size, nrr_size); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_SIZE); - return; - } - - if (system.GetApplicationProcessProgramID() != header.application_id) { - LOG_ERROR(Service_LDR, - "Attempting to load NRR with title ID other than current process. (actual " - "{:016X})!", - header.application_id); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_NRR); - return; - } - - std::vector<SHA256Hash> hashes; - - // Copy all hashes in the NRR (specified by hash count/hash offset) into vector. - for (std::size_t i = header.hash_offset; - i < (header.hash_offset + (header.hash_count * sizeof(SHA256Hash))); i += 8) { - SHA256Hash hash; - std::memcpy(hash.data(), nrr_data.data() + i, sizeof(SHA256Hash)); - hashes.emplace_back(hash); - } - - nrr.insert_or_assign(nrr_address, std::move(hashes)); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - - void UnregisterModuleInfo(HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const auto pid = rp.Pop<u64>(); - const auto nrr_address = rp.Pop<VAddr>(); - - LOG_DEBUG(Service_LDR, "called with pid={}, nrr_address={:016X}", pid, nrr_address); - - nrr.erase(nrr_address); - - IPC::ResponseBuilder rb{ctx, 2}; - - rb.Push(ResultSuccess); - } - - bool ValidateRegionForMap(Kernel::KProcessPageTable& page_table, VAddr start, - std::size_t size) const { - const std::size_t padding_size{page_table.GetNumGuardPages() * Kernel::PageSize}; - - Kernel::KMemoryInfo start_info; - Kernel::Svc::PageInfo page_info; - R_ASSERT( - page_table.QueryInfo(std::addressof(start_info), std::addressof(page_info), start - 1)); - - if (start_info.GetState() != Kernel::KMemoryState::Free) { - return {}; - } - - if (start_info.GetAddress() > (start - padding_size)) { - return {}; - } - - Kernel::KMemoryInfo end_info; - R_ASSERT(page_table.QueryInfo(std::addressof(end_info), std::addressof(page_info), - start + size)); - - if (end_info.GetState() != Kernel::KMemoryState::Free) { - return {}; - } - - return (start + size + padding_size) <= (end_info.GetAddress() + end_info.GetSize()); - } - - Result GetAvailableMapRegion(Kernel::KProcessPageTable& page_table, u64 size, VAddr& out_addr) { - size = Common::AlignUp(size, Kernel::PageSize); - size += page_table.GetNumGuardPages() * Kernel::PageSize * 4; - - const auto is_region_available = [&](VAddr addr) { - const auto end_addr = addr + size; - while (addr < end_addr) { - if (system.ApplicationMemory().IsValidVirtualAddress(addr)) { - return false; - } - - if (!page_table.Contains(out_addr, size)) { - return false; - } - - if (page_table.IsInHeapRegion(out_addr, size)) { - return false; - } - - if (page_table.IsInAliasRegion(out_addr, size)) { - return false; - } - - addr += Kernel::PageSize; - } - return true; - }; - - bool succeeded = false; - const auto map_region_end = - GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize(); - while (current_map_addr < map_region_end) { - if (is_region_available(current_map_addr)) { - succeeded = true; - break; - } - current_map_addr += 0x100000; - } - - if (!succeeded) { - ASSERT_MSG(false, "Out of address space!"); - return Kernel::ResultOutOfMemory; - } - - out_addr = current_map_addr; - current_map_addr += size; - - return ResultSuccess; - } - - Result MapProcessCodeMemory(VAddr* out_map_location, Kernel::KProcess* process, VAddr base_addr, - u64 size) { - auto& page_table{process->GetPageTable()}; - VAddr addr{}; - - for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { - R_TRY(GetAvailableMapRegion(page_table, size, addr)); - - const Result result{page_table.MapCodeMemory(addr, base_addr, size)}; - if (result == Kernel::ResultInvalidCurrentMemory) { - continue; - } - - R_TRY(result); - - if (ValidateRegionForMap(page_table, addr, size)) { - *out_map_location = addr; - return ResultSuccess; - } - } - - return ERROR_INSUFFICIENT_ADDRESS_SPACE; - } - - Result MapNro(VAddr* out_map_location, Kernel::KProcess* process, VAddr nro_addr, - std::size_t nro_size, VAddr bss_addr, std::size_t bss_size, std::size_t size) { - for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { - auto& page_table{process->GetPageTable()}; - VAddr addr{}; - - R_TRY(MapProcessCodeMemory(&addr, process, nro_addr, nro_size)); - - if (bss_size) { - auto block_guard = detail::ScopeExit([&] { - page_table.UnmapCodeMemory(addr + nro_size, bss_addr, bss_size); - page_table.UnmapCodeMemory(addr, nro_addr, nro_size); - }); - - const Result result{page_table.MapCodeMemory(addr + nro_size, bss_addr, bss_size)}; - - if (result == Kernel::ResultInvalidCurrentMemory) { - continue; - } - - if (result.IsError()) { - return result; - } - - block_guard.Cancel(); - } - - if (ValidateRegionForMap(page_table, addr, size)) { - *out_map_location = addr; - return ResultSuccess; - } - } - - return ERROR_INSUFFICIENT_ADDRESS_SPACE; - } - - Result LoadNro(Kernel::KProcess* process, const NROHeader& nro_header, VAddr nro_addr, - VAddr start) const { - const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset}; - const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset}; - const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset}; - const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size}; - const VAddr bss_end_addr{ - Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)}; - - const auto CopyCode = [this](VAddr src_addr, VAddr dst_addr, u64 size) { - system.ApplicationMemory().CopyBlock(dst_addr, src_addr, size); - }; - CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start, - nro_header.segment_headers[TEXT_INDEX].memory_size); - CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start, - nro_header.segment_headers[RO_INDEX].memory_size); - CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start, - nro_header.segment_headers[DATA_INDEX].memory_size); - - R_TRY(process->GetPageTable().SetProcessMemoryPermission( - text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute)); - R_TRY(process->GetPageTable().SetProcessMemoryPermission( - ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read)); - - return process->GetPageTable().SetProcessMemoryPermission( - data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite); - } - - void LoadModule(HLERequestContext& ctx) { - struct Parameters { - u64_le process_id; - u64_le image_address; - u64_le image_size; - u64_le bss_address; - u64_le bss_size; - }; - - IPC::RequestParser rp{ctx}; - const auto [process_id, nro_address, nro_size, bss_address, bss_size] = - rp.PopRaw<Parameters>(); - - LOG_DEBUG(Service_LDR, - "called with pid={:016X}, nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, " - "bss_size={:016X}", - process_id, nro_address, nro_size, bss_address, bss_size); - - if (!initialized) { - LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NOT_INITIALIZED); - return; - } - - if (nro.size() >= MAXIMUM_LOADED_RO) { - LOG_ERROR(Service_LDR, "Loading new NRO would exceed the maximum number of loaded NROs " - "(0x40)! Failing..."); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_MAXIMUM_NRO); - return; - } - - // NRO Address does not fall on 0x1000 byte boundary - if (!Common::Is4KBAligned(nro_address)) { - LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", - nro_address); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ALIGNMENT); - return; - } - - // NRO Size or BSS Size is zero or causes overflow - const auto nro_size_valid = - nro_size != 0 && nro_address + nro_size > nro_address && Common::Is4KBAligned(nro_size); - const auto bss_size_valid = nro_size + bss_size >= nro_size && - (bss_size == 0 || bss_address + bss_size > bss_address); - - if (!nro_size_valid || !bss_size_valid) { - LOG_ERROR(Service_LDR, - "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, " - "bss_address={:016X}, bss_size={:016X})", - nro_address, nro_size, bss_address, bss_size); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_SIZE); - return; - } - - // Read NRO data from memory - std::vector<u8> nro_data(nro_size); - system.ApplicationMemory().ReadBlock(nro_address, nro_data.data(), nro_size); - - SHA256Hash hash{}; - mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0); - - // NRO Hash is already loaded - if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) { - return info.second.hash == hash; - })) { - LOG_ERROR(Service_LDR, "NRO is already loaded!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_ALREADY_LOADED); - return; - } - - // NRO Hash is not in any loaded NRR - if (!IsValidNROHash(hash)) { - LOG_ERROR(Service_LDR, - "NRO hash is not present in any currently loaded NRRs (hash={})!", - Common::HexToString(hash)); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_MISSING_NRR_HASH); - return; - } - - // Load and validate the NRO header - NROHeader header{}; - std::memcpy(&header, nro_data.data(), sizeof(NROHeader)); - if (!IsValidNRO(header, nro_size, bss_size)) { - LOG_ERROR(Service_LDR, "NRO was invalid!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_NRO); - return; - } - - // Map memory for the NRO - VAddr map_location{}; - const auto map_result{MapNro(&map_location, system.ApplicationProcess(), nro_address, - nro_size, bss_address, bss_size, nro_size + bss_size)}; - if (map_result != ResultSuccess) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(map_result); - } - - // Load the NRO into the mapped memory - if (const auto result{ - LoadNro(system.ApplicationProcess(), header, nro_address, map_location)}; - result.IsError()) { - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(result); - } - - // Track the loaded NRO - nro.insert_or_assign(map_location, - NROInfo{hash, map_location, nro_size, bss_address, bss_size, - header.segment_headers[TEXT_INDEX].memory_size, - header.segment_headers[RO_INDEX].memory_size, - header.segment_headers[DATA_INDEX].memory_size, nro_address}); - - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push(map_location); - } - - Result UnmapNro(const NROInfo& info) { - // Each region must be unmapped separately to validate memory state - auto& page_table{system.ApplicationProcess()->GetPageTable()}; - - if (info.bss_size != 0) { - R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size + - info.data_size, - info.bss_address, info.bss_size)); - } - - R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size, - info.src_addr + info.text_size + info.ro_size, - info.data_size)); - R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size, - info.src_addr + info.text_size, info.ro_size)); - R_TRY(page_table.UnmapCodeMemory(info.nro_address, info.src_addr, info.text_size)); - return ResultSuccess; - } - - void UnloadModule(HLERequestContext& ctx) { - if (!initialized) { - LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_NOT_INITIALIZED); - return; - } - - struct Parameters { - u64_le process_id; - u64_le nro_address; - }; - - IPC::RequestParser rp{ctx}; - const auto [process_id, nro_address] = rp.PopRaw<Parameters>(); - LOG_DEBUG(Service_LDR, "called with process_id={:016X}, nro_address=0x{:016X}", process_id, - nro_address); - - if (!Common::Is4KBAligned(nro_address)) { - LOG_ERROR(Service_LDR, "NRO address has invalid alignment (nro_address=0x{:016X})", - nro_address); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_ALIGNMENT); - return; - } - - const auto iter = nro.find(nro_address); - if (iter == nro.end()) { - LOG_ERROR(Service_LDR, - "The NRO attempting to be unmapped was not mapped or has an invalid address " - "(nro_address=0x{:016X})!", - nro_address); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_INVALID_NRO_ADDRESS); - return; - } - - const auto result{UnmapNro(iter->second)}; - - nro.erase(iter); - - IPC::ResponseBuilder rb{ctx, 2}; - - rb.Push(result); - } - - void Initialize(HLERequestContext& ctx) { - LOG_WARNING(Service_LDR, "(STUBBED) called"); - - initialized = true; - current_map_addr = - GetInteger(system.ApplicationProcess()->GetPageTable().GetAliasCodeRegionStart()); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - -private: - bool initialized{}; - - std::map<VAddr, NROInfo> nro; - std::map<VAddr, std::vector<SHA256Hash>> nrr; - VAddr current_map_addr{}; - - bool IsValidNROHash(const SHA256Hash& hash) const { - return std::any_of(nrr.begin(), nrr.end(), [&hash](const auto& p) { - return std::find(p.second.begin(), p.second.end(), hash) != p.second.end(); - }); - } - - static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) { - return header.magic == Common::MakeMagic('N', 'R', 'O', '0') && - header.nro_size == nro_size && header.bss_size == bss_size && - - header.segment_headers[RO_INDEX].memory_offset == - header.segment_headers[TEXT_INDEX].memory_offset + - header.segment_headers[TEXT_INDEX].memory_size && - - header.segment_headers[DATA_INDEX].memory_offset == - header.segment_headers[RO_INDEX].memory_offset + - header.segment_headers[RO_INDEX].memory_size && - - nro_size == header.segment_headers[DATA_INDEX].memory_offset + - header.segment_headers[DATA_INDEX].memory_size && - - Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size) && - Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) && - Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size); - } -}; - void LoopProcess(Core::System& system) { auto server_manager = std::make_unique<ServerManager>(system); server_manager->RegisterNamedService("ldr:dmnt", std::make_shared<DebugMonitor>(system)); server_manager->RegisterNamedService("ldr:pm", std::make_shared<ProcessManager>(system)); server_manager->RegisterNamedService("ldr:shel", std::make_shared<Shell>(system)); - server_manager->RegisterNamedService("ldr:ro", std::make_shared<RelocatableObject>(system)); ServerManager::RunServer(std::move(server_manager)); } 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 buffer->height = SharedBufferHeight; buffer->stride = SharedBufferBlockLinearStride; buffer->format = SharedBufferBlockLinearFormat; + buffer->external_format = SharedBufferBlockLinearFormat; buffer->buffer_id = handle; buffer->offset = slot * SharedBufferSlotSize; 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <mbedtls/sha256.h> + +#include "common/scope_exit.h" +#include "core/hle/kernel/k_process.h" + +#include "core/hle/service/ipc_helpers.h" +#include "core/hle/service/ro/ro.h" +#include "core/hle/service/ro/ro_nro_utils.h" +#include "core/hle/service/ro/ro_results.h" +#include "core/hle/service/ro/ro_types.h" +#include "core/hle/service/server_manager.h" +#include "core/hle/service/service.h" + +namespace Service::RO { + +namespace { + +// Convenience definitions. +constexpr size_t MaxSessions = 0x3; +constexpr size_t MaxNrrInfos = 0x40; +constexpr size_t MaxNroInfos = 0x40; + +constexpr u64 InvalidProcessId = 0xffffffffffffffffULL; +constexpr u64 InvalidContextId = 0xffffffffffffffffULL; + +// Types. +using Sha256Hash = std::array<u8, 32>; + +struct NroInfo { + u64 base_address; + u64 nro_heap_address; + u64 nro_heap_size; + u64 bss_heap_address; + u64 bss_heap_size; + u64 code_size; + u64 rw_size; + ModuleId module_id; +}; + +struct NrrInfo { + u64 nrr_heap_address; + u64 nrr_heap_size; + + // Verification. + std::vector<Sha256Hash> hashes; +}; + +struct ProcessContext { + constexpr ProcessContext() = default; + + void Initialize(Kernel::KProcess* process, u64 process_id) { + ASSERT(!m_in_use); + + m_nro_in_use = {}; + m_nrr_in_use = {}; + m_nro_infos = {}; + m_nrr_infos = {}; + + m_process = process; + m_process_id = process_id; + m_in_use = true; + + if (m_process) { + m_process->Open(); + } + } + + void Finalize() { + ASSERT(m_in_use); + + if (m_process) { + m_process->Close(); + } + + m_nro_in_use = {}; + m_nrr_in_use = {}; + m_nro_infos = {}; + m_nrr_infos = {}; + + m_process = nullptr; + m_process_id = InvalidProcessId; + m_in_use = false; + } + + Kernel::KProcess* GetProcess() const { + return m_process; + } + + u64 GetProcessId() const { + return m_process_id; + } + + bool IsFree() const { + return !m_in_use; + } + + u64 GetProgramId(Kernel::KProcess* other_process) const { + // Automatically select a handle, allowing for override. + if (other_process) { + return other_process->GetProgramId(); + } else if (m_process) { + return m_process->GetProgramId(); + } else { + return 0; + } + } + + Result GetNrrInfoByAddress(NrrInfo** out, u64 nrr_heap_address) { + for (size_t i = 0; i < MaxNrrInfos; i++) { + if (m_nrr_in_use[i] && m_nrr_infos[i].nrr_heap_address == nrr_heap_address) { + if (out != nullptr) { + *out = std::addressof(m_nrr_infos[i]); + } + R_SUCCEED(); + } + } + R_THROW(RO::ResultNotRegistered); + } + + Result GetFreeNrrInfo(NrrInfo** out) { + for (size_t i = 0; i < MaxNrrInfos; i++) { + if (!m_nrr_in_use[i]) { + if (out != nullptr) { + *out = std::addressof(m_nrr_infos[i]); + } + R_SUCCEED(); + } + } + R_THROW(RO::ResultTooManyNrr); + } + + Result GetNroInfoByAddress(NroInfo** out, u64 nro_address) { + for (size_t i = 0; i < MaxNroInfos; i++) { + if (m_nro_in_use[i] && m_nro_infos[i].base_address == nro_address) { + if (out != nullptr) { + *out = std::addressof(m_nro_infos[i]); + } + R_SUCCEED(); + } + } + R_THROW(RO::ResultNotLoaded); + } + + Result GetNroInfoByModuleId(NroInfo** out, const ModuleId* module_id) { + for (size_t i = 0; i < MaxNroInfos; i++) { + if (m_nro_in_use[i] && std::memcmp(std::addressof(m_nro_infos[i].module_id), module_id, + sizeof(*module_id)) == 0) { + if (out != nullptr) { + *out = std::addressof(m_nro_infos[i]); + } + R_SUCCEED(); + } + } + R_THROW(RO::ResultNotLoaded); + } + + Result GetFreeNroInfo(NroInfo** out) { + for (size_t i = 0; i < MaxNroInfos; i++) { + if (!m_nro_in_use[i]) { + if (out != nullptr) { + *out = std::addressof(m_nro_infos[i]); + } + R_SUCCEED(); + } + } + R_THROW(RO::ResultTooManyNro); + } + + Result ValidateHasNroHash(u64 base_address, const NroHeader* nro_header) const { + // Calculate hash. + Sha256Hash hash; + { + const u64 size = nro_header->GetSize(); + + std::vector<u8> nro_data(size); + m_process->GetMemory().ReadBlock(base_address, nro_data.data(), size); + + mbedtls_sha256_ret(nro_data.data(), size, hash.data(), 0); + } + + for (size_t i = 0; i < MaxNrrInfos; i++) { + // Ensure we only check NRRs that are used. + if (!m_nrr_in_use[i]) { + continue; + } + + // Locate the hash within the hash list. + const auto hash_it = std::ranges::find(m_nrr_infos[i].hashes, hash); + if (hash_it == m_nrr_infos[i].hashes.end()) { + continue; + } + + // The hash is valid! + R_SUCCEED(); + } + + R_THROW(RO::ResultNotAuthorized); + } + + Result ValidateNro(ModuleId* out_module_id, u64* out_rx_size, u64* out_ro_size, + u64* out_rw_size, u64 base_address, u64 expected_nro_size, + u64 expected_bss_size) { + // Ensure we have a process to work on. + R_UNLESS(m_process != nullptr, RO::ResultInvalidProcess); + + // Read the NRO header. + NroHeader header{}; + m_process->GetMemory().ReadBlock(base_address, std::addressof(header), sizeof(header)); + + // Validate header. + R_UNLESS(header.IsMagicValid(), RO::ResultInvalidNro); + + // Read sizes from header. + const u64 nro_size = header.GetSize(); + const u64 text_ofs = header.GetTextOffset(); + const u64 text_size = header.GetTextSize(); + const u64 ro_ofs = header.GetRoOffset(); + const u64 ro_size = header.GetRoSize(); + const u64 rw_ofs = header.GetRwOffset(); + const u64 rw_size = header.GetRwSize(); + const u64 bss_size = header.GetBssSize(); + + // Validate sizes meet expected. + R_UNLESS(nro_size == expected_nro_size, RO::ResultInvalidNro); + R_UNLESS(bss_size == expected_bss_size, RO::ResultInvalidNro); + + // Validate all sizes are aligned. + R_UNLESS(Common::IsAligned(text_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro); + R_UNLESS(Common::IsAligned(ro_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro); + R_UNLESS(Common::IsAligned(rw_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro); + R_UNLESS(Common::IsAligned(bss_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro); + + // Validate sections are in order. + R_UNLESS(text_ofs <= ro_ofs, RO::ResultInvalidNro); + R_UNLESS(ro_ofs <= rw_ofs, RO::ResultInvalidNro); + + // Validate sections are sequential and contiguous. + R_UNLESS(text_ofs == 0, RO::ResultInvalidNro); + R_UNLESS(text_ofs + text_size == ro_ofs, RO::ResultInvalidNro); + R_UNLESS(ro_ofs + ro_size == rw_ofs, RO::ResultInvalidNro); + R_UNLESS(rw_ofs + rw_size == nro_size, RO::ResultInvalidNro); + + // Verify NRO hash. + R_TRY(this->ValidateHasNroHash(base_address, std::addressof(header))); + + // Check if NRO has already been loaded. + const ModuleId* module_id = header.GetModuleId(); + R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), RO::ResultAlreadyLoaded); + + // Apply patches to NRO. + // LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8*>(mapped_memory), nro_size); + + // Copy to output. + *out_module_id = *module_id; + *out_rx_size = text_size; + *out_ro_size = ro_size; + *out_rw_size = rw_size; + R_SUCCEED(); + } + + void SetNrrInfoInUse(const NrrInfo* info, bool in_use) { + ASSERT(std::addressof(m_nrr_infos[0]) <= info && + info <= std::addressof(m_nrr_infos[MaxNrrInfos - 1])); + const size_t index = info - std::addressof(m_nrr_infos[0]); + m_nrr_in_use[index] = in_use; + } + + void SetNroInfoInUse(const NroInfo* info, bool in_use) { + ASSERT(std::addressof(m_nro_infos[0]) <= info && + info <= std::addressof(m_nro_infos[MaxNroInfos - 1])); + const size_t index = info - std::addressof(m_nro_infos[0]); + m_nro_in_use[index] = in_use; + } + +private: + std::array<bool, MaxNroInfos> m_nro_in_use{}; + std::array<bool, MaxNrrInfos> m_nrr_in_use{}; + std::array<NroInfo, MaxNroInfos> m_nro_infos{}; + std::array<NrrInfo, MaxNrrInfos> m_nrr_infos{}; + Kernel::KProcess* m_process{}; + u64 m_process_id{InvalidProcessId}; + bool m_in_use{}; +}; + +Result ValidateAddressAndNonZeroSize(u64 address, u64 size) { + R_UNLESS(Common::IsAligned(address, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidAddress); + R_UNLESS(size != 0, RO::ResultInvalidSize); + R_UNLESS(Common::IsAligned(size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidSize); + R_UNLESS(address < address + size, RO::ResultInvalidSize); + R_SUCCEED(); +} + +Result ValidateAddressAndSize(u64 address, u64 size) { + R_UNLESS(Common::IsAligned(address, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidAddress); + R_UNLESS(Common::IsAligned(size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidSize); + R_UNLESS(size == 0 || address < address + size, RO::ResultInvalidSize); + R_SUCCEED(); +} + +class RoContext { +public: + explicit RoContext() = default; + + Result RegisterProcess(size_t* out_context_id, Kernel::KProcess* process, u64 process_id) { + // Validate process id. + R_UNLESS(process->GetProcessId() == process_id, RO::ResultInvalidProcess); + + // Check if a process context already exists. + R_UNLESS(this->GetContextByProcessId(process_id) == nullptr, RO::ResultInvalidSession); + + // Allocate a context to manage the process handle. + *out_context_id = this->AllocateContext(process, process_id); + + R_SUCCEED(); + } + + Result ValidateProcess(size_t context_id, u64 process_id) { + const ProcessContext* ctx = this->GetContextById(context_id); + R_UNLESS(ctx != nullptr, RO::ResultInvalidProcess); + R_UNLESS(ctx->GetProcessId() == process_id, RO::ResultInvalidProcess); + R_SUCCEED(); + } + + void UnregisterProcess(size_t context_id) { + this->FreeContext(context_id); + } + + Result RegisterModuleInfo(size_t context_id, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind, + bool enforce_nrr_kind) { + // Get context. + ProcessContext* context = this->GetContextById(context_id); + ASSERT(context != nullptr); + + // Validate address/size. + R_TRY(ValidateAddressAndNonZeroSize(nrr_address, nrr_size)); + + // Check we have space for a new NRR. + NrrInfo* nrr_info = nullptr; + R_TRY(context->GetFreeNrrInfo(std::addressof(nrr_info))); + + // Ensure we have a valid process to read from. + Kernel::KProcess* process = context->GetProcess(); + R_UNLESS(process != nullptr, RO::ResultInvalidProcess); + + // Read NRR. + NrrHeader header{}; + process->GetMemory().ReadBlock(nrr_address, std::addressof(header), sizeof(header)); + + // Set NRR info. + context->SetNrrInfoInUse(nrr_info, true); + nrr_info->nrr_heap_address = nrr_address; + nrr_info->nrr_heap_size = nrr_size; + + // Read NRR hash list. + nrr_info->hashes.resize(header.GetNumHashes()); + process->GetMemory().ReadBlock(nrr_address + header.GetHashesOffset(), + nrr_info->hashes.data(), + sizeof(Sha256Hash) * header.GetNumHashes()); + + R_SUCCEED(); + } + + Result UnregisterModuleInfo(size_t context_id, u64 nrr_address) { + // Get context. + ProcessContext* context = this->GetContextById(context_id); + ASSERT(context != nullptr); + + // Validate address. + R_UNLESS(Common::IsAligned(nrr_address, Core::Memory::YUZU_PAGESIZE), + RO::ResultInvalidAddress); + + // Check the NRR is loaded. + NrrInfo* nrr_info = nullptr; + R_TRY(context->GetNrrInfoByAddress(std::addressof(nrr_info), nrr_address)); + + // Nintendo does this unconditionally, whether or not the actual unmap succeeds. + context->SetNrrInfoInUse(nrr_info, false); + *nrr_info = {}; + + R_SUCCEED(); + } + + Result MapManualLoadModuleMemory(u64* out_address, size_t context_id, u64 nro_address, + u64 nro_size, u64 bss_address, u64 bss_size) { + // Get context. + ProcessContext* context = this->GetContextById(context_id); + ASSERT(context != nullptr); + + // Validate address/size. + R_TRY(ValidateAddressAndNonZeroSize(nro_address, nro_size)); + R_TRY(ValidateAddressAndSize(bss_address, bss_size)); + + const u64 total_size = nro_size + bss_size; + R_UNLESS(total_size >= nro_size, RO::ResultInvalidSize); + R_UNLESS(total_size >= bss_size, RO::ResultInvalidSize); + + // Check we have space for a new NRO. + NroInfo* nro_info = nullptr; + R_TRY(context->GetFreeNroInfo(std::addressof(nro_info))); + nro_info->nro_heap_address = nro_address; + nro_info->nro_heap_size = nro_size; + nro_info->bss_heap_address = bss_address; + nro_info->bss_heap_size = bss_size; + + // Map the NRO. + R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcess(), nro_address, + nro_size, bss_address, bss_size, generate_random)); + ON_RESULT_FAILURE { + UnmapNro(context->GetProcess(), nro_info->base_address, nro_address, nro_size, + bss_address, bss_size); + }; + + // Validate the NRO (parsing region extents). + u64 rx_size = 0, ro_size = 0, rw_size = 0; + R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size), + std::addressof(ro_size), std::addressof(rw_size), + nro_info->base_address, nro_size, bss_size)); + + // Set NRO perms. + R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size, + rw_size + bss_size)); + + context->SetNroInfoInUse(nro_info, true); + nro_info->code_size = rx_size + ro_size; + nro_info->rw_size = rw_size; + *out_address = nro_info->base_address; + R_SUCCEED(); + } + + Result UnmapManualLoadModuleMemory(size_t context_id, u64 nro_address) { + // Get context. + ProcessContext* context = this->GetContextById(context_id); + ASSERT(context != nullptr); + + // Validate address. + R_UNLESS(Common::IsAligned(nro_address, Core::Memory::YUZU_PAGESIZE), + RO::ResultInvalidAddress); + + // Check the NRO is loaded. + NroInfo* nro_info = nullptr; + R_TRY(context->GetNroInfoByAddress(std::addressof(nro_info), nro_address)); + + // Unmap. + const NroInfo nro_backup = *nro_info; + { + // Nintendo does this unconditionally, whether or not the actual unmap succeeds. + context->SetNroInfoInUse(nro_info, false); + std::memset(nro_info, 0, sizeof(*nro_info)); + } + R_RETURN(UnmapNro(context->GetProcess(), nro_backup.base_address, + nro_backup.nro_heap_address, nro_backup.code_size + nro_backup.rw_size, + nro_backup.bss_heap_address, nro_backup.bss_heap_size)); + } + +private: + std::array<ProcessContext, MaxSessions> process_contexts; + std::mt19937_64 generate_random; + + // Context Helpers. + ProcessContext* GetContextById(size_t context_id) { + if (context_id == InvalidContextId) { + return nullptr; + } + + ASSERT(context_id < process_contexts.size()); + return std::addressof(process_contexts[context_id]); + } + + ProcessContext* GetContextByProcessId(u64 process_id) { + for (size_t i = 0; i < MaxSessions; i++) { + if (process_contexts[i].GetProcessId() == process_id) { + return std::addressof(process_contexts[i]); + } + } + return nullptr; + } + + size_t AllocateContext(Kernel::KProcess* process, u64 process_id) { + // Find a free process context. + for (size_t i = 0; i < MaxSessions; i++) { + ProcessContext* context = std::addressof(process_contexts[i]); + + if (context->IsFree()) { + context->Initialize(process, process_id); + return i; + } + } + + // Failure to find a free context is actually an abort condition. + UNREACHABLE(); + } + + void FreeContext(size_t context_id) { + if (ProcessContext* context = GetContextById(context_id); context != nullptr) { + context->Finalize(); + } + } +}; + +class RoInterface { +public: + explicit RoInterface(std::shared_ptr<RoContext> ro, NrrKind nrr_kind) + : m_ro(ro), m_context_id(InvalidContextId), m_nrr_kind(nrr_kind) {} + ~RoInterface() { + m_ro->UnregisterProcess(m_context_id); + } + + Result MapManualLoadModuleMemory(u64* out_load_address, u64 client_pid, u64 nro_address, + u64 nro_size, u64 bss_address, u64 bss_size) { + R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address, m_context_id, nro_address, + nro_size, bss_address, bss_size)); + } + + Result UnmapManualLoadModuleMemory(u64 client_pid, u64 nro_address) { + R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + R_RETURN(m_ro->UnmapManualLoadModuleMemory(m_context_id, nro_address)); + } + + Result RegisterModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size) { + R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + R_RETURN( + m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, NrrKind::User, true)); + } + + Result UnregisterModuleInfo(u64 client_pid, u64 nrr_address) { + R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + R_RETURN(m_ro->UnregisterModuleInfo(m_context_id, nrr_address)); + } + + Result RegisterProcessHandle(u64 client_pid, Kernel::KProcess* process) { + // Register the process. + R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process, client_pid)); + } + + Result RegisterProcessModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size, + Kernel::KProcess* process) { + // Validate the process. + R_TRY(m_ro->ValidateProcess(m_context_id, client_pid)); + + // Register the module. + R_RETURN(m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, m_nrr_kind, + m_nrr_kind == NrrKind::JitPlugin)); + } + +private: + std::shared_ptr<RoContext> m_ro{}; + size_t m_context_id{}; + NrrKind m_nrr_kind{}; +}; + +class IRoInterface : public ServiceFramework<IRoInterface> { +public: + explicit IRoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro, + NrrKind nrr_kind) + : ServiceFramework{system_, name_}, interface { + ro, nrr_kind + } { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IRoInterface::MapManualLoadModuleMemory, "MapManualLoadModuleMemory"}, + {1, &IRoInterface::UnmapManualLoadModuleMemory, "UnmapManualLoadModuleMemory"}, + {2, &IRoInterface::RegisterModuleInfo, "RegisterModuleInfo"}, + {3, &IRoInterface::UnregisterModuleInfo, "UnregisterModuleInfo"}, + {4, &IRoInterface::RegisterProcessHandle, "RegisterProcessHandle"}, + {10, &IRoInterface::RegisterProcessModuleInfo, "RegisterProcessModuleInfo"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void MapManualLoadModuleMemory(HLERequestContext& ctx) { + LOG_DEBUG(Service_LDR, "(called)"); + + struct InputParameters { + u64 client_pid; + u64 nro_address; + u64 nro_size; + u64 bss_address; + u64 bss_size; + }; + + IPC::RequestParser rp{ctx}; + auto params = rp.PopRaw<InputParameters>(); + + u64 load_address = 0; + auto result = interface.MapManualLoadModuleMemory(&load_address, ctx.GetPID(), + params.nro_address, params.nro_size, + params.bss_address, params.bss_size); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(result); + rb.Push(load_address); + } + + void UnmapManualLoadModuleMemory(HLERequestContext& ctx) { + LOG_DEBUG(Service_LDR, "(called)"); + + struct InputParameters { + u64 client_pid; + u64 nro_address; + }; + + IPC::RequestParser rp{ctx}; + auto params = rp.PopRaw<InputParameters>(); + auto result = interface.UnmapManualLoadModuleMemory(ctx.GetPID(), params.nro_address); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + } + + void RegisterModuleInfo(HLERequestContext& ctx) { + LOG_DEBUG(Service_LDR, "(called)"); + + struct InputParameters { + u64 client_pid; + u64 nrr_address; + u64 nrr_size; + }; + + IPC::RequestParser rp{ctx}; + auto params = rp.PopRaw<InputParameters>(); + auto result = + interface.RegisterModuleInfo(ctx.GetPID(), params.nrr_address, params.nrr_size); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + } + + void UnregisterModuleInfo(HLERequestContext& ctx) { + LOG_DEBUG(Service_LDR, "(called)"); + + struct InputParameters { + u64 client_pid; + u64 nrr_address; + }; + + IPC::RequestParser rp{ctx}; + auto params = rp.PopRaw<InputParameters>(); + auto result = interface.UnregisterModuleInfo(ctx.GetPID(), params.nrr_address); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + } + + void RegisterProcessHandle(HLERequestContext& ctx) { + LOG_DEBUG(Service_LDR, "(called)"); + + auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); + auto client_pid = ctx.GetPID(); + auto result = interface.RegisterProcessHandle(client_pid, + process_h->DynamicCast<Kernel::KProcess*>()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + } + + void RegisterProcessModuleInfo(HLERequestContext& ctx) { + LOG_DEBUG(Service_LDR, "(called)"); + + struct InputParameters { + u64 client_pid; + u64 nrr_address; + u64 nrr_size; + }; + + IPC::RequestParser rp{ctx}; + auto params = rp.PopRaw<InputParameters>(); + auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0)); + + auto client_pid = ctx.GetPID(); + auto result = + interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size, + process_h->DynamicCast<Kernel::KProcess*>()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + } + + RoInterface interface; +}; + +} // namespace + +void LoopProcess(Core::System& system) { + auto server_manager = std::make_unique<ServerManager>(system); + + auto ro = std::make_shared<RoContext>(); + + const auto RoInterfaceFactoryForUser = [&, ro] { + return std::make_shared<IRoInterface>(system, "ldr:ro", ro, NrrKind::User); + }; + + const auto RoInterfaceFactoryForJitPlugin = [&, ro] { + return std::make_shared<IRoInterface>(system, "ro:1", ro, NrrKind::JitPlugin); + }; + + server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser)); + server_manager->RegisterNamedService("ro:1", std::move(RoInterfaceFactoryForJitPlugin)); + + ServerManager::RunServer(std::move(server_manager)); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +namespace Core { +class System; +} + +namespace Service::RO { + +void LoopProcess(Core::System& system); + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/kernel/k_process.h" +#include "core/hle/service/ro/ro_nro_utils.h" +#include "core/hle/service/ro/ro_results.h" + +namespace Service::RO { + +namespace { + +struct ProcessMemoryRegion { + u64 address; + u64 size; +}; + +size_t GetTotalProcessMemoryRegionSize(const ProcessMemoryRegion* regions, size_t num_regions) { + size_t total = 0; + + for (size_t i = 0; i < num_regions; ++i) { + total += regions[i].size; + } + + return total; +} + +size_t SetupNroProcessMemoryRegions(ProcessMemoryRegion* regions, u64 nro_heap_address, + u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size) { + // Reset region count. + size_t num_regions = 0; + + // We always want a region for the nro. + regions[num_regions++] = {nro_heap_address, nro_heap_size}; + + // If we have bss, create a region for bss. + if (bss_heap_size > 0) { + regions[num_regions++] = {bss_heap_address, bss_heap_size}; + } + + return num_regions; +} + +Result SetProcessMemoryPermission(Kernel::KProcess* process, u64 address, u64 size, + Kernel::Svc::MemoryPermission permission) { + auto& page_table = process->GetPageTable(); + + // Set permission. + R_RETURN(page_table.SetProcessMemoryPermission(address, size, permission)); +} + +Result UnmapProcessCodeMemory(Kernel::KProcess* process, u64 process_code_address, + const ProcessMemoryRegion* regions, size_t num_regions) { + // Get the total process memory region size. + const size_t total_size = GetTotalProcessMemoryRegionSize(regions, num_regions); + + auto& page_table = process->GetPageTable(); + + // Unmap each region in order. + size_t cur_offset = total_size; + for (size_t i = 0; i < num_regions; ++i) { + // We want to unmap in reverse order. + const auto& cur_region = regions[num_regions - 1 - i]; + + // Subtract to update the current offset. + cur_offset -= cur_region.size; + + // Unmap. + R_TRY(page_table.UnmapCodeMemory(process_code_address + cur_offset, cur_region.address, + cur_region.size)); + } + + R_SUCCEED(); +} + +Result EnsureGuardPages(Kernel::KProcessPageTable& page_table, u64 map_address, u64 map_size) { + Kernel::KMemoryInfo memory_info; + Kernel::Svc::PageInfo page_info; + + // Ensure page before mapping is unmapped. + R_TRY(page_table.QueryInfo(std::addressof(memory_info), std::addressof(page_info), + map_address - 1)); + R_UNLESS(memory_info.GetSvcState() == Kernel::Svc::MemoryState::Free, + Kernel::ResultInvalidState); + + // Ensure page after mapping is unmapped. + R_TRY(page_table.QueryInfo(std::addressof(memory_info), std::addressof(page_info), + map_address + map_size)); + R_UNLESS(memory_info.GetSvcState() == Kernel::Svc::MemoryState::Free, + Kernel::ResultInvalidState); + + // Successfully verified guard pages. + R_SUCCEED(); +} + +Result MapProcessCodeMemory(u64* out, Kernel::KProcess* process, const ProcessMemoryRegion* regions, + size_t num_regions, std::mt19937_64& generate_random) { + auto& page_table = process->GetPageTable(); + const u64 alias_code_start = + GetInteger(page_table.GetAliasCodeRegionStart()) / Kernel::PageSize; + const u64 alias_code_size = page_table.GetAliasCodeRegionSize() / Kernel::PageSize; + + for (size_t trial = 0; trial < 64; trial++) { + // Generate a new trial address. + const u64 mapped_address = + (alias_code_start + (generate_random() % alias_code_size)) * Kernel::PageSize; + + const auto MapRegions = [&] { + // Map the regions in order. + u64 mapped_size = 0; + for (size_t i = 0; i < num_regions; ++i) { + // If we fail, unmap up to where we've mapped. + ON_RESULT_FAILURE { + R_ASSERT(UnmapProcessCodeMemory(process, mapped_address, regions, i)); + }; + + // Map the current region. + R_TRY(page_table.MapCodeMemory(mapped_address + mapped_size, regions[i].address, + regions[i].size)); + + mapped_size += regions[i].size; + } + + // If we fail, unmap all mapped regions. + ON_RESULT_FAILURE { + R_ASSERT(UnmapProcessCodeMemory(process, mapped_address, regions, num_regions)); + }; + + // Ensure guard pages. + R_RETURN(EnsureGuardPages(page_table, mapped_address, mapped_size)); + }; + + if (R_SUCCEEDED(MapRegions())) { + // Set the output address. + *out = mapped_address; + R_SUCCEED(); + } + } + + // We failed to map anything. + R_THROW(RO::ResultOutOfAddressSpace); +} + +} // namespace + +Result MapNro(u64* out_base_address, Kernel::KProcess* process, u64 nro_heap_address, + u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size, + std::mt19937_64& generate_random) { + // Set up the process memory regions. + std::array<ProcessMemoryRegion, 2> regions{}; + const size_t num_regions = SetupNroProcessMemoryRegions( + regions.data(), nro_heap_address, nro_heap_size, bss_heap_address, bss_heap_size); + + // Re-map the nro/bss as code memory in the destination process. + R_RETURN(MapProcessCodeMemory(out_base_address, process, regions.data(), num_regions, + generate_random)); +} + +Result SetNroPerms(Kernel::KProcess* process, u64 base_address, u64 rx_size, u64 ro_size, + u64 rw_size) { + const u64 rx_offset = 0; + const u64 ro_offset = rx_offset + rx_size; + const u64 rw_offset = ro_offset + ro_size; + + R_TRY(SetProcessMemoryPermission(process, base_address + rx_offset, rx_size, + Kernel::Svc::MemoryPermission::ReadExecute)); + R_TRY(SetProcessMemoryPermission(process, base_address + ro_offset, ro_size, + Kernel::Svc::MemoryPermission::Read)); + R_TRY(SetProcessMemoryPermission(process, base_address + rw_offset, rw_size, + Kernel::Svc::MemoryPermission::ReadWrite)); + + R_SUCCEED(); +} + +Result UnmapNro(Kernel::KProcess* process, u64 base_address, u64 nro_heap_address, + u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size) { + // Set up the process memory regions. + std::array<ProcessMemoryRegion, 2> regions{}; + const size_t num_regions = SetupNroProcessMemoryRegions( + regions.data(), nro_heap_address, nro_heap_size, bss_heap_address, bss_heap_size); + + // Unmap the nro/bss. + R_RETURN(UnmapProcessCodeMemory(process, base_address, regions.data(), num_regions)); +} + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <random> + +#include "common/common_types.h" + +namespace Kernel { +class KProcess; +} + +union Result; + +namespace Service::RO { + +Result MapNro(u64* out_base_address, Kernel::KProcess* process, u64 nro_heap_address, + u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size, + std::mt19937_64& generate_random); +Result SetNroPerms(Kernel::KProcess* process, u64 base_address, u64 rx_size, u64 ro_size, + u64 rw_size); +Result UnmapNro(Kernel::KProcess* process, u64 base_address, u64 nro_heap_address, + u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size); + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/result.h" + +namespace Service::RO { + +constexpr Result ResultOutOfAddressSpace{ErrorModule::RO, 2}; +constexpr Result ResultAlreadyLoaded{ErrorModule::RO, 3}; +constexpr Result ResultInvalidNro{ErrorModule::RO, 4}; +constexpr Result ResultInvalidNrr{ErrorModule::RO, 6}; +constexpr Result ResultTooManyNro{ErrorModule::RO, 7}; +constexpr Result ResultTooManyNrr{ErrorModule::RO, 8}; +constexpr Result ResultNotAuthorized{ErrorModule::RO, 9}; +constexpr Result ResultInvalidNrrKind{ErrorModule::RO, 10}; +constexpr Result ResultInternalError{ErrorModule::RO, 1023}; +constexpr Result ResultInvalidAddress{ErrorModule::RO, 1025}; +constexpr Result ResultInvalidSize{ErrorModule::RO, 1026}; +constexpr Result ResultNotLoaded{ErrorModule::RO, 1028}; +constexpr Result ResultNotRegistered{ErrorModule::RO, 1029}; +constexpr Result ResultInvalidSession{ErrorModule::RO, 1030}; +constexpr Result ResultInvalidProcess{ErrorModule::RO, 1031}; + +} // 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 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" + +namespace Service::RO { + +enum class NrrKind : u8 { + User = 0, + JitPlugin = 1, + Count, +}; + +static constexpr size_t ModuleIdSize = 0x20; +struct ModuleId { + std::array<u8, ModuleIdSize> data; +}; +static_assert(sizeof(ModuleId) == ModuleIdSize); + +struct NrrCertification { + static constexpr size_t RsaKeySize = 0x100; + static constexpr size_t SignedSize = 0x120; + + u64 program_id_mask; + u64 program_id_pattern; + std::array<u8, 0x10> reserved_10; + std::array<u8, RsaKeySize> modulus; + std::array<u8, RsaKeySize> signature; +}; +static_assert(sizeof(NrrCertification) == + NrrCertification::RsaKeySize + NrrCertification::SignedSize); + +class NrrHeader { +public: + static constexpr u32 Magic = Common::MakeMagic('N', 'R', 'R', '0'); + +public: + bool IsMagicValid() const { + return m_magic == Magic; + } + + bool IsProgramIdValid() const { + return (m_program_id & m_certification.program_id_mask) == + m_certification.program_id_pattern; + } + + NrrKind GetNrrKind() const { + const NrrKind kind = static_cast<NrrKind>(m_nrr_kind); + ASSERT(kind < NrrKind::Count); + return kind; + } + + u64 GetProgramId() const { + return m_program_id; + } + + u32 GetSize() const { + return m_size; + } + + u32 GetNumHashes() const { + return m_num_hashes; + } + + size_t GetHashesOffset() const { + return m_hashes_offset; + } + + u32 GetKeyGeneration() const { + return m_key_generation; + } + + const u8* GetCertificationSignature() const { + return m_certification.signature.data(); + } + + const u8* GetCertificationSignedArea() const { + return reinterpret_cast<const u8*>(std::addressof(m_certification)); + } + + const u8* GetCertificationModulus() const { + return m_certification.modulus.data(); + } + + const u8* GetSignature() const { + return m_signature.data(); + } + + size_t GetSignedAreaSize() const { + return m_size - GetSignedAreaOffset(); + } + + static constexpr size_t GetSignedAreaOffset() { + return offsetof(NrrHeader, m_program_id); + } + +private: + u32 m_magic; + u32 m_key_generation; + INSERT_PADDING_BYTES_NOINIT(8); + NrrCertification m_certification; + std::array<u8, 0x100> m_signature; + u64 m_program_id; + u32 m_size; + u8 m_nrr_kind; // 7.0.0+ + INSERT_PADDING_BYTES_NOINIT(3); + u32 m_hashes_offset; + u32 m_num_hashes; + INSERT_PADDING_BYTES_NOINIT(8); +}; +static_assert(sizeof(NrrHeader) == 0x350, "NrrHeader has wrong size"); + +class NroHeader { +public: + static constexpr u32 Magic = Common::MakeMagic('N', 'R', 'O', '0'); + +public: + bool IsMagicValid() const { + return m_magic == Magic; + } + + u32 GetSize() const { + return m_size; + } + + u32 GetTextOffset() const { + return m_text_offset; + } + + u32 GetTextSize() const { + return m_text_size; + } + + u32 GetRoOffset() const { + return m_ro_offset; + } + + u32 GetRoSize() const { + return m_ro_size; + } + + u32 GetRwOffset() const { + return m_rw_offset; + } + + u32 GetRwSize() const { + return m_rw_size; + } + + u32 GetBssSize() const { + return m_bss_size; + } + + const ModuleId* GetModuleId() const { + return std::addressof(m_module_id); + } + +private: + u32 m_entrypoint_insn; + u32 m_mod_offset; + INSERT_PADDING_BYTES_NOINIT(0x8); + u32 m_magic; + INSERT_PADDING_BYTES_NOINIT(0x4); + u32 m_size; + INSERT_PADDING_BYTES_NOINIT(0x4); + u32 m_text_offset; + u32 m_text_size; + u32 m_ro_offset; + u32 m_ro_size; + u32 m_rw_offset; + u32 m_rw_size; + u32 m_bss_size; + INSERT_PADDING_BYTES_NOINIT(0x4); + ModuleId m_module_id; + INSERT_PADDING_BYTES_NOINIT(0x20); +}; +static_assert(sizeof(NroHeader) == 0x80, "NroHeader has wrong size"); + +} // 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, } Result ServerManager::RegisterNamedService(const std::string& service_name, - std::shared_ptr<SessionRequestHandler>&& handler, + SessionRequestHandlerFactory&& handler_factory, u32 max_sessions) { ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); // Add the new server to sm:. ASSERT(R_SUCCEEDED( - m_system.ServiceManager().RegisterService(service_name, max_sessions, handler))); + m_system.ServiceManager().RegisterService(service_name, max_sessions, handler_factory))); // Get the registered port. Kernel::KPort* port{}; @@ -112,7 +112,7 @@ Result ServerManager::RegisterNamedService(const std::string& service_name, // Begin tracking the server port. { std::scoped_lock ll{m_list_mutex}; - m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler)); + m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory)); } // Signal the wakeup event. @@ -121,8 +121,18 @@ Result ServerManager::RegisterNamedService(const std::string& service_name, R_SUCCEED(); } +Result ServerManager::RegisterNamedService(const std::string& service_name, + std::shared_ptr<SessionRequestHandler>&& handler, + u32 max_sessions) { + // Make the factory. + const auto HandlerFactory = [handler]() { return handler; }; + + // Register the service with the new factory. + R_RETURN(this->RegisterNamedService(service_name, std::move(HandlerFactory), max_sessions)); +} + Result ServerManager::ManageNamedPort(const std::string& service_name, - std::shared_ptr<SessionRequestHandler>&& handler, + SessionRequestHandlerFactory&& handler_factory, u32 max_sessions) { ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); @@ -149,7 +159,7 @@ Result ServerManager::ManageNamedPort(const std::string& service_name, // Begin tracking the server port. { std::scoped_lock ll{m_list_mutex}; - m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler)); + m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory)); } // We succeeded. @@ -269,13 +279,13 @@ Result ServerManager::WaitAndProcessImpl() { case HandleType::Port: { // Port signaled. auto* port = wait_obj->DynamicCast<Kernel::KServerPort*>(); - std::shared_ptr<SessionRequestHandler> handler; + SessionRequestHandlerFactory handler_factory; // Remove from tracking. { std::scoped_lock ll{m_list_mutex}; ASSERT(m_ports.contains(port)); - m_ports.at(port).swap(handler); + m_ports.at(port).swap(handler_factory); m_ports.erase(port); } @@ -283,7 +293,7 @@ Result ServerManager::WaitAndProcessImpl() { sl.unlock(); // Finish. - R_RETURN(this->OnPortEvent(port, std::move(handler))); + R_RETURN(this->OnPortEvent(port, std::move(handler_factory))); } case HandleType::Session: { // Session signaled. @@ -333,19 +343,19 @@ Result ServerManager::WaitAndProcessImpl() { } Result ServerManager::OnPortEvent(Kernel::KServerPort* port, - std::shared_ptr<SessionRequestHandler>&& handler) { + SessionRequestHandlerFactory&& handler_factory) { // Accept a new server session. Kernel::KServerSession* session = port->AcceptSession(); ASSERT(session != nullptr); // Create the session manager and install the handler. auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this); - manager->SetSessionHandler(std::shared_ptr(handler)); + manager->SetSessionHandler(handler_factory()); // Track the server session. { std::scoped_lock ll{m_list_mutex}; - m_ports.emplace(port, std::move(handler)); + m_ports.emplace(port, std::move(handler_factory)); m_sessions.emplace(session, std::move(manager)); } 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 @@ #include "common/polyfill_thread.h" #include "common/thread.h" #include "core/hle/result.h" +#include "core/hle/service/hle_ipc.h" #include "core/hle/service/mutex.h" namespace Core { @@ -28,10 +29,6 @@ class KSynchronizationObject; namespace Service { -class HLERequestContext; -class SessionRequestHandler; -class SessionRequestManager; - class ServerManager { public: explicit ServerManager(Core::System& system); @@ -40,10 +37,13 @@ public: Result RegisterSession(Kernel::KServerSession* session, std::shared_ptr<SessionRequestManager> manager); Result RegisterNamedService(const std::string& service_name, + SessionRequestHandlerFactory&& handler_factory, + u32 max_sessions = 64); + Result RegisterNamedService(const std::string& service_name, std::shared_ptr<SessionRequestHandler>&& handler, u32 max_sessions = 64); Result ManageNamedPort(const std::string& service_name, - std::shared_ptr<SessionRequestHandler>&& handler, u32 max_sessions = 64); + SessionRequestHandlerFactory&& handler_factory, u32 max_sessions = 64); Result ManageDeferral(Kernel::KEvent** out_event); Result LoopProcess(); @@ -56,7 +56,7 @@ private: Result LoopProcessImpl(); Result WaitAndProcessImpl(); - Result OnPortEvent(Kernel::KServerPort* port, std::shared_ptr<SessionRequestHandler>&& handler); + Result OnPortEvent(Kernel::KServerPort* port, SessionRequestHandlerFactory&& handler_factory); Result OnSessionEvent(Kernel::KServerSession* session, std::shared_ptr<SessionRequestManager>&& manager); Result OnDeferralEvent(std::list<RequestState>&& deferrals); @@ -68,7 +68,7 @@ private: std::mutex m_list_mutex; // Guest state tracking - std::map<Kernel::KServerPort*, std::shared_ptr<SessionRequestHandler>> m_ports{}; + std::map<Kernel::KServerPort*, SessionRequestHandlerFactory> m_ports{}; std::map<Kernel::KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{}; Kernel::KEvent* m_event{}; 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 @@ #include "core/hle/service/prepo/prepo.h" #include "core/hle/service/psc/psc.h" #include "core/hle/service/ptm/ptm.h" +#include "core/hle/service/ro/ro.h" #include "core/hle/service/service.h" #include "core/hle/service/set/settings.h" #include "core/hle/service/sm/sm.h" @@ -270,6 +271,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); }); + kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); }); kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); }); 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) { } Result ServiceManager::RegisterService(std::string name, u32 max_sessions, - SessionRequestHandlerPtr handler) { + SessionRequestHandlerFactory handler) { R_TRY(ValidateServiceName(name)); std::scoped_lock lk{lock}; @@ -121,7 +121,7 @@ void SM::Initialize(HLERequestContext& ctx) { rb.Push(ResultSuccess); } -void SM::GetService(HLERequestContext& ctx) { +void SM::GetServiceCmif(HLERequestContext& ctx) { Kernel::KClientSession* client_session{}; auto result = GetServiceImpl(&client_session, ctx); if (ctx.GetIsDeferred()) { @@ -192,19 +192,32 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques return result; } - LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); - *out_client_session = session; return ResultSuccess; } -void SM::RegisterService(HLERequestContext& ctx) { +void SM::RegisterServiceCmif(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; std::string name(PopServiceName(rp)); const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); const auto max_session_count = rp.PopRaw<u32>(); + this->RegisterServiceImpl(ctx, name, max_session_count, is_light); +} + +void SM::RegisterServiceTipc(HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + std::string name(PopServiceName(rp)); + + const auto max_session_count = rp.PopRaw<u32>(); + const auto is_light = static_cast<bool>(rp.PopRaw<u32>()); + + this->RegisterServiceImpl(ctx, name, max_session_count, is_light); +} + +void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count, + bool is_light) { LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, max_session_count, is_light); @@ -240,15 +253,15 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_) service_manager{service_manager_}, kernel{system_.Kernel()} { RegisterHandlers({ {0, &SM::Initialize, "Initialize"}, - {1, &SM::GetService, "GetService"}, - {2, &SM::RegisterService, "RegisterService"}, + {1, &SM::GetServiceCmif, "GetService"}, + {2, &SM::RegisterServiceCmif, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, {4, nullptr, "DetachClient"}, }); RegisterHandlersTipc({ {0, &SM::Initialize, "Initialize"}, {1, &SM::GetServiceTipc, "GetService"}, - {2, &SM::RegisterService, "RegisterService"}, + {2, &SM::RegisterServiceTipc, "RegisterService"}, {3, &SM::UnregisterService, "UnregisterService"}, {4, nullptr, "DetachClient"}, }); @@ -264,7 +277,9 @@ void LoopProcess(Core::System& system) { server_manager->ManageDeferral(&deferral_event); service_manager.SetDeferralEvent(deferral_event); - server_manager->ManageNamedPort("sm:", std::make_shared<SM>(system.ServiceManager(), system)); + auto sm_service = std::make_shared<SM>(system.ServiceManager(), system); + server_manager->ManageNamedPort("sm:", [sm_service] { return sm_service; }); + ServerManager::RunServer(std::move(server_manager)); } 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: private: void Initialize(HLERequestContext& ctx); - void GetService(HLERequestContext& ctx); + void GetServiceCmif(HLERequestContext& ctx); void GetServiceTipc(HLERequestContext& ctx); - void RegisterService(HLERequestContext& ctx); + void RegisterServiceCmif(HLERequestContext& ctx); + void RegisterServiceTipc(HLERequestContext& ctx); void UnregisterService(HLERequestContext& ctx); Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx); + void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count, + bool is_light); ServiceManager& service_manager; Kernel::KernelCore& kernel; @@ -53,7 +56,8 @@ public: explicit ServiceManager(Kernel::KernelCore& kernel_); ~ServiceManager(); - Result RegisterService(std::string name, u32 max_sessions, SessionRequestHandlerPtr handler); + Result RegisterService(std::string name, u32 max_sessions, + SessionRequestHandlerFactory handler_factory); Result UnregisterService(const std::string& name); Result GetServicePort(Kernel::KPort** out_port, const std::string& name); @@ -64,7 +68,7 @@ public: LOG_DEBUG(Service, "Can't find service: {}", service_name); return nullptr; } - return std::static_pointer_cast<T>(service->second); + return std::static_pointer_cast<T>(service->second()); } void InvokeControlRequest(HLERequestContext& context); @@ -79,7 +83,7 @@ private: /// Map of registered services, retrieved using GetServicePort. std::mutex lock; - std::unordered_map<std::string, SessionRequestHandlerPtr> registered_services; + std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services; std::unordered_map<std::string, Kernel::KPort*> service_ports; /// 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: return ret; } - Result ReadImpl(std::vector<u8>* out_data, size_t size) { + Result ReadImpl(std::vector<u8>* out_data) { ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; }); size_t actual_size{}; Result res = backend->Read(&actual_size, *out_data); @@ -326,8 +326,8 @@ private: } void Read(HLERequestContext& ctx) { - std::vector<u8> output_bytes; - const Result res = ReadImpl(&output_bytes, ctx.GetWriteBufferSize()); + std::vector<u8> output_bytes(ctx.GetWriteBufferSize()); + const Result res = ReadImpl(&output_bytes); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(res); 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 struct Memory::Impl { explicit Impl(Core::System& system_) : system{system_} {} - void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { + void SetCurrentPageTable(Kernel::KProcess& process) { current_page_table = &process.GetPageTable().GetImpl(); current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer(); - - const std::size_t address_space_width = process.GetPageTable().GetAddressSpaceWidth(); - - system.ArmInterface(core_id).PageTableChanged(*current_page_table, address_space_width); } void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, @@ -871,8 +867,8 @@ void Memory::Reset() { impl = std::make_unique<Impl>(system); } -void Memory::SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { - impl->SetCurrentPageTable(process, core_id); +void Memory::SetCurrentPageTable(Kernel::KProcess& process) { + impl->SetCurrentPageTable(process); } void 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: * * @param process The process to use the page table of. */ - void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id); + void SetCurrentPageTable(Kernel::KProcess& process); /** * 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() { } const auto applet_resource = hid->GetResourceManager(); - if (applet_resource == nullptr) { + if (applet_resource == nullptr || applet_resource->GetNpad() == nullptr) { LOG_WARNING(CheatEngine, "Attempted to read input state, but applet resource is not initialized!"); 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 return out; } -json GetProcessorStateDataAuto(Core::System& system) { - const auto* process{system.ApplicationProcess()}; - auto& arm{system.CurrentArmInterface()}; - - Core::ARM_Interface::ThreadContext64 context{}; - arm.SaveContext(context); - - return GetProcessorStateData(process->Is64Bit() ? "AArch64" : "AArch32", - GetInteger(process->GetEntryPoint()), context.sp, context.pc, - context.pstate, context.cpu_registers); -} - -json GetBacktraceData(Core::System& system) { - auto out = json::array(); - const auto& backtrace{system.CurrentArmInterface().GetBacktrace()}; - for (const auto& entry : backtrace) { - out.push_back({ - {"module", entry.module}, - {"address", fmt::format("{:016X}", entry.address)}, - {"original_address", fmt::format("{:016X}", entry.original_address)}, - {"offset", fmt::format("{:016X}", entry.offset)}, - {"symbol_name", entry.name}, - }); - } - - return out; -} - json GetFullDataAuto(const std::string& timestamp, u64 title_id, Core::System& system) { json out; out["yuzu_version"] = GetYuzuVersionData(); out["report_common"] = GetReportCommonData(title_id, ResultSuccess, timestamp); - out["processor_state"] = GetProcessorStateDataAuto(system); - out["backtrace"] = GetBacktraceData(system); return out; } @@ -351,8 +321,6 @@ void Reporter::SaveErrorReport(u64 title_id, Result result, out["yuzu_version"] = GetYuzuVersionData(); out["report_common"] = GetReportCommonData(title_id, result, timestamp); - out["processor_state"] = GetProcessorStateDataAuto(system); - out["backtrace"] = GetBacktraceData(system); out["error_custom_text"] = { {"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; class RasterizerInterface { public: - void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { + void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) { const u64 page_start{addr >> Core::Memory::YUZU_PAGEBITS}; const u64 page_end{(addr + size + Core::Memory::YUZU_PAGESIZE - 1) >> Core::Memory::YUZU_PAGEBITS}; for (u64 page = page_start; page < page_end; ++page) { int& value = page_table[page]; - value += delta; + value += (cache ? 1 : -1); if (value < 0) { throw std::logic_error{"negative page"}; } @@ -546,4 +546,4 @@ TEST_CASE("MemoryTracker: Cached write downloads") { REQUIRE(!memory_track->IsRegionGpuModified(c + PAGE, PAGE)); memory_track->MarkRegionAsCpuModified(c, WORD); REQUIRE(rasterizer.Count() == 0); -}
\ No newline at end of file +} 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: VAddr addr = cpu_addr + word_index * BYTES_PER_WORD; IteratePages(changed_bits, [&](size_t offset, size_t size) { rasterizer->UpdatePagesCachedCount(addr + offset * BYTES_PER_PAGE, - size * BYTES_PER_PAGE, add_to_rasterizer ? 1 : -1); + size * BYTES_PER_PAGE, add_to_rasterizer); }); } 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) { return false; } - *out_is_interlaced = frame->interlaced_frame != 0; + *out_is_interlaced = +#if defined(FF_API_INTERLACED_FRAME) || LIBAVUTIL_VERSION_MAJOR >= 59 + (frame->flags & AV_FRAME_FLAG_INTERLACED) != 0; +#else + frame->interlaced_frame != 0; +#endif return true; }; 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 @@ #include <atomic> +#include "common/alignment.h" #include "common/assert.h" #include "common/common_types.h" #include "common/div_ceil.h" @@ -11,61 +12,65 @@ namespace VideoCore { +static constexpr u16 IdentityValue = 1; + using namespace Core::Memory; -RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) - : cached_pages(std::make_unique<CachedPages>()), cpu_memory{cpu_memory_} {} +RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) : map{}, cpu_memory{cpu_memory_} { + // We are tracking CPU memory, which cannot map more than 39 bits. + const VAddr start_address = 0; + const VAddr end_address = (1ULL << 39); + const IntervalType address_space_interval(start_address, end_address); + const auto value = std::make_pair(address_space_interval, IdentityValue); + + map.add(value); +} RasterizerAccelerated::~RasterizerAccelerated() = default; -void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { - u64 uncache_begin = 0; - u64 cache_begin = 0; - u64 uncache_bytes = 0; - u64 cache_bytes = 0; - - std::atomic_thread_fence(std::memory_order_acquire); - const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE); - for (u64 page = addr >> YUZU_PAGEBITS; page != page_end; ++page) { - std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page); - - if (delta > 0) { - ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!"); - } else if (delta < 0) { - ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!"); - } else { - ASSERT_MSG(false, "Delta must be non-zero!"); - } +void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) { + std::scoped_lock lk{map_lock}; - // Adds or subtracts 1, as count is a unsigned 8-bit value - count.fetch_add(static_cast<u16>(delta), std::memory_order_release); - - // Assume delta is either -1 or 1 - if (count.load(std::memory_order::relaxed) == 0) { - if (uncache_bytes == 0) { - uncache_begin = page; - } - uncache_bytes += YUZU_PAGESIZE; - } else if (uncache_bytes > 0) { - cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, - false); - uncache_bytes = 0; - } - if (count.load(std::memory_order::relaxed) == 1 && delta > 0) { - if (cache_bytes == 0) { - cache_begin = page; - } - cache_bytes += YUZU_PAGESIZE; - } else if (cache_bytes > 0) { - cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true); - cache_bytes = 0; + // Align sizes. + addr = Common::AlignDown(addr, YUZU_PAGESIZE); + size = Common::AlignUp(size, YUZU_PAGESIZE); + + // Declare the overall interval we are going to operate on. + const VAddr start_address = addr; + const VAddr end_address = addr + size; + const IntervalType modification_range(start_address, end_address); + + // Find the boundaries of where to iterate. + const auto lower = map.lower_bound(modification_range); + const auto upper = map.upper_bound(modification_range); + + // Iterate over the contained intervals. + for (auto it = lower; it != upper; it++) { + // Intersect interval range with modification range. + const auto current_range = modification_range & it->first; + + // Calculate the address and size to operate over. + const auto current_addr = current_range.lower(); + const auto current_size = current_range.upper() - current_addr; + + // Get the current value of the range. + const auto value = it->second; + + if (cache && value == IdentityValue) { + // If we are going to cache, and the value is not yet referenced, then cache this range. + cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, true); + } else if (!cache && value == IdentityValue + 1) { + // If we are going to uncache, and this is the last reference, then uncache this range. + cpu_memory.RasterizerMarkRegionCached(current_addr, current_size, false); } } - if (uncache_bytes > 0) { - cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, false); - } - if (cache_bytes > 0) { - cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true); + + // Update the set. + const auto value = std::make_pair(modification_range, IdentityValue); + if (cache) { + map.add(value); + } else { + map.subtract(value); } } 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 @@ #pragma once -#include <array> -#include <atomic> +#include <mutex> +#include <boost/icl/interval_map.hpp> #include "common/common_types.h" #include "video_core/rasterizer_interface.h" @@ -21,28 +21,17 @@ public: explicit RasterizerAccelerated(Core::Memory::Memory& cpu_memory_); ~RasterizerAccelerated() override; - void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) override; + void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) override; private: - class CacheEntry final { - public: - CacheEntry() = default; + using PageIndex = VAddr; + using PageReferenceCount = u16; - std::atomic_uint16_t& Count(std::size_t page) { - return values[page & 3]; - } + using IntervalMap = boost::icl::interval_map<PageIndex, PageReferenceCount>; + using IntervalType = IntervalMap::interval_type; - const std::atomic_uint16_t& Count(std::size_t page) const { - return values[page & 3]; - } - - private: - std::array<std::atomic_uint16_t, 4> values{}; - }; - static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!"); - - using CachedPages = std::array<CacheEntry, 0x2000000>; - std::unique_ptr<CachedPages> cached_pages; + IntervalMap map; + std::mutex map_lock; Core::Memory::Memory& cpu_memory; }; 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: } /// Increase/decrease the number of object in pages touching the specified region - virtual void UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {} + virtual void UpdatePagesCachedCount(VAddr addr, u64 size, bool cache) {} /// Initialize disk cached resources for the game being emulated 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, MICROPROFILE_SCOPE(OpenGL_CacheManagement); std::scoped_lock lock{texture_cache.mutex}; - ImageView* const image_view{texture_cache.TryFindFramebufferImageView(framebuffer_addr)}; + ImageView* const image_view{ + texture_cache.TryFindFramebufferImageView(config, framebuffer_addr)}; if (!image_view) { return false; } @@ -725,7 +726,6 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config, screen_info.texture.width = image_view->size.width; screen_info.texture.height = image_view->size.height; screen_info.display_texture = image_view->Handle(Shader::TextureType::Color2D); - screen_info.display_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format); return true; } 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) { }; glNamedBufferSubData(vertex_buffer.handle, 0, sizeof(vertices), std::data(vertices)); - if (screen_info.display_srgb) { - glEnable(GL_FRAMEBUFFER_SRGB); - } else { - glDisable(GL_FRAMEBUFFER_SRGB); - } + glDisable(GL_FRAMEBUFFER_SRGB); glViewportIndexedf(0, 0.0f, 0.0f, static_cast<GLfloat>(layout.width), static_cast<GLfloat>(layout.height)); @@ -710,8 +706,7 @@ void RendererOpenGL::RenderScreenshot() { GLuint renderbuffer; glGenRenderbuffers(1, &renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); - glRenderbufferStorage(GL_RENDERBUFFER, screen_info.display_srgb ? GL_SRGB8 : GL_RGB8, - layout.width, layout.height); + glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); 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 { struct ScreenInfo { GLuint display_texture{}; bool was_accelerated = false; - bool display_srgb{}; const Common::Rectangle<float> display_texcoords{0.0f, 0.0f, 1.0f, 1.0f}; TextureInfo texture; }; 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_, device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), scheduler(device, state_tracker), swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, - render_window.GetFramebufferLayout().height, false), + render_window.GetFramebufferLayout().height), present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain, surface), blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, present_manager, @@ -131,11 +131,10 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; const bool use_accelerated = rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); - const bool is_srgb = use_accelerated && screen_info.is_srgb; RenderScreenshot(*framebuffer, use_accelerated); Frame* frame = present_manager.GetRenderFrame(); - blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated, is_srgb); + blit_screen.DrawToSwapchain(frame, *framebuffer, use_accelerated); scheduler.Flush(*frame->render_ready); present_manager.Present(frame); @@ -205,7 +204,7 @@ void Vulkan::RendererVulkan::RenderScreenshot(const Tegra::FramebufferConfig& fr .flags = 0, .image = *staging_image, .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = screen_info.is_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM, + .format = VK_FORMAT_B8G8R8A8_UNORM, .components{ .r = VK_COMPONENT_SWIZZLE_IDENTITY, .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 Scheduler& scheduler_, const ScreenInfo& screen_info_) : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_}, memory_allocator{memory_allocator_}, swapchain{swapchain_}, present_manager{present_manager_}, - scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_}, - current_srgb{swapchain.IsSrgb()}, image_view_format{swapchain.GetImageViewFormat()} { + scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { resource_ticks.resize(image_count); + swapchain_view_format = swapchain.GetImageViewFormat(); CreateStaticResources(); CreateDynamicResources(); @@ -480,28 +480,22 @@ void BlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, } void BlitScreen::DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, - bool use_accelerated, bool is_srgb) { - // Recreate dynamic resources if the the image count or colorspace changed + bool use_accelerated) { + // Recreate dynamic resources if the the image count or input format changed + const VkFormat current_framebuffer_format = + std::exchange(framebuffer_view_format, GetFormat(framebuffer)); if (const std::size_t swapchain_images = swapchain.GetImageCount(); - swapchain_images != image_count || current_srgb != is_srgb) { - current_srgb = is_srgb; -#ifdef ANDROID - // Android is already ordered the same as Switch. - image_view_format = current_srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; -#else - image_view_format = current_srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; -#endif + swapchain_images != image_count || current_framebuffer_format != framebuffer_view_format) { image_count = swapchain_images; Recreate(); } // Recreate the presentation frame if the dimensions of the window changed const Layout::FramebufferLayout layout = render_window.GetFramebufferLayout(); - if (layout.width != frame->width || layout.height != frame->height || - is_srgb != frame->is_srgb) { + if (layout.width != frame->width || layout.height != frame->height) { Recreate(); - present_manager.RecreateFrame(frame, layout.width, layout.height, is_srgb, - image_view_format, *renderpass); + present_manager.RecreateFrame(frame, layout.width, layout.height, swapchain_view_format, + *renderpass); } const VkExtent2D render_area{frame->width, frame->height}; @@ -629,7 +623,7 @@ void BlitScreen::CreateDescriptorPool() { } void BlitScreen::CreateRenderPass() { - renderpass = CreateRenderPassImpl(image_view_format); + renderpass = CreateRenderPassImpl(swapchain_view_format); } vk::RenderPass BlitScreen::CreateRenderPassImpl(VkFormat format) { @@ -1149,7 +1143,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { .pNext = nullptr, .flags = 0, .imageType = VK_IMAGE_TYPE_2D, - .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer), + .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format, .extent = { .width = (up_scale * framebuffer.width) >> down_shift, @@ -1174,7 +1168,7 @@ void BlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { .flags = 0, .image = *image, .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : GetFormat(framebuffer), + .format = used_on_framebuffer ? VK_FORMAT_R16G16B16A16_SFLOAT : framebuffer_view_format, .components = { .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 { VkImageView image_view{}; u32 width{}; u32 height{}; - bool is_srgb{}; }; class BlitScreen { @@ -69,7 +68,7 @@ public: const Layout::FramebufferLayout layout, VkExtent2D render_area, bool use_accelerated); void DrawToSwapchain(Frame* frame, const Tegra::FramebufferConfig& framebuffer, - bool use_accelerated, bool is_srgb); + bool use_accelerated); [[nodiscard]] vk::Framebuffer CreateFramebuffer(const VkImageView& image_view, VkExtent2D extent); @@ -161,8 +160,8 @@ private: u32 raw_width = 0; u32 raw_height = 0; Service::android::PixelFormat pixel_format{}; - bool current_srgb; - VkFormat image_view_format; + VkFormat framebuffer_view_format; + VkFormat swapchain_view_format; std::unique_ptr<FSR> fsr; 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) { }); } -void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb, - VkFormat image_view_format, VkRenderPass rd) { +void PresentManager::RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format, + VkRenderPass rd) { auto& dld = device.GetLogical(); frame->width = width; frame->height = height; - frame->is_srgb = is_srgb; frame->image = memory_allocator.CreateImage({ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, @@ -289,7 +288,7 @@ void PresentManager::PresentThread(std::stop_token token) { } void PresentManager::RecreateSwapchain(Frame* frame) { - swapchain.Create(*surface, frame->width, frame->height, frame->is_srgb); + swapchain.Create(*surface, frame->width, frame->height); image_count = swapchain.GetImageCount(); } @@ -319,12 +318,12 @@ void PresentManager::CopyToSwapchain(Frame* frame) { void PresentManager::CopyToSwapchainImpl(Frame* frame) { MICROPROFILE_SCOPE(Vulkan_CopyToSwapchain); - // If the size or colorspace of the incoming frames has changed, recreate the swapchain + // If the size of the incoming frames has changed, recreate the swapchain // to account for that. - const bool srgb_changed = swapchain.NeedsRecreation(frame->is_srgb); + const bool is_suboptimal = swapchain.NeedsRecreation(); const bool size_changed = swapchain.GetWidth() != frame->width || swapchain.GetHeight() != frame->height; - if (srgb_changed || size_changed) { + if (is_suboptimal || size_changed) { RecreateSwapchain(frame); } 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; struct Frame { u32 width; u32 height; - bool is_srgb; vk::Image image; vk::ImageView image_view; vk::Framebuffer framebuffer; @@ -48,8 +47,8 @@ public: void Present(Frame* frame); /// Recreates the present frame to match the provided parameters - void RecreateFrame(Frame* frame, u32 width, u32 height, bool is_srgb, - VkFormat image_view_format, VkRenderPass rd); + void RecreateFrame(Frame* frame, u32 width, u32 height, VkFormat image_view_format, + VkRenderPass rd); /// Waits for the present thread to finish presenting all queued frames. 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, return false; } std::scoped_lock lock{texture_cache.mutex}; - ImageView* const image_view = texture_cache.TryFindFramebufferImageView(framebuffer_addr); + ImageView* const image_view = + texture_cache.TryFindFramebufferImageView(config, framebuffer_addr); if (!image_view) { return false; } @@ -792,7 +793,6 @@ bool RasterizerVulkan::AccelerateDisplay(const Tegra::FramebufferConfig& config, screen_info.image_view = image_view->Handle(Shader::TextureType::Color2D); screen_info.width = image_view->size.width; screen_info.height = image_view->size.height; - screen_info.is_srgb = VideoCore::Surface::IsPixelFormatSRGB(image_view->format); return true; } 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 } // Anonymous namespace Swapchain::Swapchain(VkSurfaceKHR surface_, const Device& device_, Scheduler& scheduler_, - u32 width_, u32 height_, bool srgb) + u32 width_, u32 height_) : surface{surface_}, device{device_}, scheduler{scheduler_} { - Create(surface_, width_, height_, srgb); + Create(surface_, width_, height_); } Swapchain::~Swapchain() = default; -void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_, bool srgb) { +void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_) { is_outdated = false; is_suboptimal = false; width = width_; @@ -127,7 +127,7 @@ void Swapchain::Create(VkSurfaceKHR surface_, u32 width_, u32 height_, bool srgb Destroy(); - CreateSwapchain(capabilities, srgb); + CreateSwapchain(capabilities); CreateSemaphores(); resource_ticks.clear(); @@ -196,7 +196,7 @@ void Swapchain::Present(VkSemaphore render_semaphore) { } } -void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { +void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { const auto physical_device{device.GetPhysical()}; const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface); @@ -274,15 +274,14 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); extent = swapchain_ci.imageExtent; - current_srgb = srgb; images = swapchain.GetImages(); image_count = static_cast<u32>(images.size()); #ifdef ANDROID // Android is already ordered the same as Switch. - image_view_format = srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; + image_view_format = VK_FORMAT_R8G8B8A8_UNORM; #else - image_view_format = srgb ? VK_FORMAT_B8G8R8A8_SRGB : VK_FORMAT_B8G8R8A8_UNORM; + image_view_format = VK_FORMAT_B8G8R8A8_UNORM; #endif } 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; class Swapchain { public: explicit Swapchain(VkSurfaceKHR surface, const Device& device, Scheduler& scheduler, u32 width, - u32 height, bool srgb); + u32 height); ~Swapchain(); /// Creates (or recreates) the swapchain with a given size. - void Create(VkSurfaceKHR surface, u32 width, u32 height, bool srgb); + void Create(VkSurfaceKHR surface, u32 width, u32 height); /// Acquires the next image in the swapchain, waits as needed. bool AcquireNextImage(); @@ -33,13 +33,8 @@ public: void Present(VkSemaphore render_semaphore); /// Returns true when the swapchain needs to be recreated. - bool NeedsRecreation(bool is_srgb) const { - return HasColorSpaceChanged(is_srgb) || IsSubOptimal() || NeedsPresentModeUpdate(); - } - - /// Returns true when the color space has changed. - bool HasColorSpaceChanged(bool is_srgb) const { - return current_srgb != is_srgb; + bool NeedsRecreation() const { + return IsSubOptimal() || NeedsPresentModeUpdate(); } /// Returns true when the swapchain is outdated. @@ -52,11 +47,6 @@ public: return is_suboptimal; } - /// Returns true when the swapchain format is in the srgb color space - bool IsSrgb() const { - return current_srgb; - } - VkExtent2D GetSize() const { return extent; } @@ -110,7 +100,7 @@ public: } private: - void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb); + void CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities); void CreateSemaphores(); void CreateImageViews(); @@ -144,7 +134,6 @@ private: bool has_mailbox{false}; bool has_fifo_relaxed{false}; - bool current_srgb{}; bool is_outdated{}; bool is_suboptimal{}; }; 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 storage.push_back(std::move(data)); - rasterizer.UpdatePagesCachedCount(addr, size, 1); + rasterizer.UpdatePagesCachedCount(addr, size, true); } void ShaderCache::InvalidatePagesInRegion(VAddr addr, size_t size) { @@ -209,7 +209,7 @@ void ShaderCache::UnmarkMemory(Entry* entry) { const VAddr addr = entry->addr_start; const size_t size = entry->addr_end - addr; - rasterizer.UpdatePagesCachedCount(addr, size, -1); + rasterizer.UpdatePagesCachedCount(addr, size, false); } void 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, } template <class P> -typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_addr) { +typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView( + const Tegra::FramebufferConfig& config, VAddr cpu_addr) { // TODO: Properly implement this const auto it = page_table.find(cpu_addr >> YUZU_PAGEBITS); if (it == page_table.end()) { return nullptr; } const auto& image_map_ids = it->second; - boost::container::small_vector<const ImageBase*, 4> valid_images; + boost::container::small_vector<ImageId, 4> valid_image_ids; for (const ImageMapId map_id : image_map_ids) { const ImageMapView& map = slot_map_views[map_id]; const ImageBase& image = slot_images[map.image_id]; @@ -729,18 +730,34 @@ typename P::ImageView* TextureCache<P>::TryFindFramebufferImageView(VAddr cpu_ad if (image.image_view_ids.empty()) { continue; } - valid_images.push_back(&image); + valid_image_ids.push_back(map.image_id); } - if (valid_images.size() == 1) [[likely]] { - return &slot_image_views[valid_images[0]->image_view_ids.at(0)]; + const auto view_format = [&]() { + switch (config.pixel_format) { + case Service::android::PixelFormat::Rgb565: + return PixelFormat::R5G6B5_UNORM; + case Service::android::PixelFormat::Bgra8888: + return PixelFormat::B8G8R8A8_UNORM; + default: + return PixelFormat::A8B8G8R8_UNORM; + } + }(); + + const auto GetImageViewForFramebuffer = [&](ImageId image_id) { + const ImageViewInfo info{ImageViewType::e2D, view_format}; + return &slot_image_views[FindOrEmplaceImageView(image_id, info)]; + }; + + if (valid_image_ids.size() == 1) [[likely]] { + return GetImageViewForFramebuffer(valid_image_ids.front()); } - if (valid_images.size() > 0) [[unlikely]] { - std::ranges::sort(valid_images, [](const auto* a, const auto* b) { - return a->modification_tick > b->modification_tick; + if (valid_image_ids.size() > 0) [[unlikely]] { + auto most_recent = std::ranges::max_element(valid_image_ids, [&](auto a, auto b) { + return slot_images[a].modification_tick < slot_images[b].modification_tick; }); - return &slot_image_views[valid_images[0]->image_view_ids.at(0)]; + return GetImageViewForFramebuffer(*most_recent); } return nullptr; @@ -2063,7 +2080,7 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) { ASSERT(False(image.flags & ImageFlagBits::Tracked)); image.flags |= ImageFlagBits::Tracked; if (False(image.flags & ImageFlagBits::Sparse)) { - rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, 1); + rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, true); return; } if (True(image.flags & ImageFlagBits::Registered)) { @@ -2074,13 +2091,13 @@ void TextureCache<P>::TrackImage(ImageBase& image, ImageId image_id) { const auto& map = slot_map_views[map_view_id]; const VAddr cpu_addr = map.cpu_addr; const std::size_t size = map.size; - rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); + rasterizer.UpdatePagesCachedCount(cpu_addr, size, true); } return; } ForEachSparseSegment(image, [this]([[maybe_unused]] GPUVAddr gpu_addr, VAddr cpu_addr, size_t size) { - rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1); + rasterizer.UpdatePagesCachedCount(cpu_addr, size, true); }); } @@ -2089,7 +2106,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) { ASSERT(True(image.flags & ImageFlagBits::Tracked)); image.flags &= ~ImageFlagBits::Tracked; if (False(image.flags & ImageFlagBits::Sparse)) { - rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, -1); + rasterizer.UpdatePagesCachedCount(image.cpu_addr, image.guest_size_bytes, false); return; } ASSERT(True(image.flags & ImageFlagBits::Registered)); @@ -2100,7 +2117,7 @@ void TextureCache<P>::UntrackImage(ImageBase& image, ImageId image_id) { const auto& map = slot_map_views[map_view_id]; const VAddr cpu_addr = map.cpu_addr; const std::size_t size = map.size; - rasterizer.UpdatePagesCachedCount(cpu_addr, size, -1); + rasterizer.UpdatePagesCachedCount(cpu_addr, size, false); } } 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: const Tegra::Engines::Fermi2D::Config& copy); /// Try to find a cached image view in the given CPU address - [[nodiscard]] ImageView* TryFindFramebufferImageView(VAddr cpu_addr); + [[nodiscard]] ImageView* TryFindFramebufferImageView(const Tegra::FramebufferConfig& config, + VAddr cpu_addr); /// Return true when there are uncommitted images to be downloaded [[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 @@ #include "common/fs/path_util.h" #include "common/string_util.h" #include "core/constants.h" +#include "core/core.h" +#include "core/hle/service/acc/profile_manager.h" #include "yuzu/applets/qt_profile_select.h" #include "yuzu/main.h" #include "yuzu/util/controller_navigation.h" @@ -47,9 +49,9 @@ QPixmap GetIcon(Common::UUID uuid) { } // Anonymous namespace QtProfileSelectionDialog::QtProfileSelectionDialog( - Core::HID::HIDCore& hid_core, QWidget* parent, + Core::System& system, QWidget* parent, const Core::Frontend::ProfileSelectParameters& parameters) - : QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) { + : QDialog(parent), profile_manager{system.GetProfileManager()} { outer_layout = new QVBoxLayout; instruction_label = new QLabel(); @@ -68,7 +70,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog( tree_view = new QTreeView; item_model = new QStandardItemModel(tree_view); tree_view->setModel(item_model); - controller_navigation = new ControllerNavigation(hid_core, this); + controller_navigation = new ControllerNavigation(system.HIDCore(), this); tree_view->setAlternatingRowColors(true); tree_view->setSelectionMode(QHeaderView::SingleSelection); @@ -106,10 +108,10 @@ QtProfileSelectionDialog::QtProfileSelectionDialog( SelectUser(tree_view->currentIndex()); }); - const auto& profiles = profile_manager->GetAllUsers(); + const auto& profiles = profile_manager.GetAllUsers(); for (const auto& user : profiles) { Service::Account::ProfileBase profile{}; - if (!profile_manager->GetProfileBase(user, profile)) + if (!profile_manager.GetProfileBase(user, profile)) continue; const auto username = Common::StringFromFixedZeroTerminatedBuffer( @@ -134,7 +136,7 @@ QtProfileSelectionDialog::~QtProfileSelectionDialog() { int QtProfileSelectionDialog::exec() { // Skip profile selection when there's only one. - if (profile_manager->GetUserCount() == 1) { + if (profile_manager.GetUserCount() == 1) { user_index = 0; return QDialog::Accepted; } 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 @@ #include <QDialog> #include <QList> #include "core/frontend/applets/profile_select.h" -#include "core/hle/service/acc/profile_manager.h" class ControllerNavigation; class GMainWindow; @@ -20,15 +19,19 @@ class QStandardItemModel; class QTreeView; class QVBoxLayout; -namespace Core::HID { -class HIDCore; -} // namespace Core::HID +namespace Core { +class System; +} + +namespace Service::Account { +class ProfileManager; +} class QtProfileSelectionDialog final : public QDialog { Q_OBJECT public: - explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent, + explicit QtProfileSelectionDialog(Core::System& system, QWidget* parent, const Core::Frontend::ProfileSelectParameters& parameters); ~QtProfileSelectionDialog() override; @@ -58,7 +61,7 @@ private: QScrollArea* scroll_area; QDialogButtonBox* buttons; - std::unique_ptr<Service::Account::ProfileManager> profile_manager; + Service::Account::ProfileManager& profile_manager; ControllerNavigation* controller_navigation = nullptr; }; 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 @@ <item row="5" column="0"> <widget class="QCheckBox" name="disable_buffer_reorder"> <property name="toolTip"> - <string><html><head/><body><p>When checked, disables reording of mapped memory uploads which allows to associate uploads with specific draws. May reduce performance in some cases.</p></body></html></string> + <string><html><head/><body><p>When checked, disables reordering of mapped memory uploads which allows to associate uploads with specific draws. May reduce performance in some cases.</p></body></html></string> </property> <property name="text"> <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 } } // Anonymous namespace -ConfigureProfileManager::ConfigureProfileManager(const Core::System& system_, QWidget* parent) +ConfigureProfileManager::ConfigureProfileManager(Core::System& system_, QWidget* parent) : QWidget(parent), ui{std::make_unique<Ui::ConfigureProfileManager>()}, - profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_} { + profile_manager{system_.GetProfileManager()}, system{system_} { ui->setupUi(this); tree_view = new QTreeView; @@ -149,10 +149,10 @@ void ConfigureProfileManager::SetConfiguration() { } void ConfigureProfileManager::PopulateUserList() { - const auto& profiles = profile_manager->GetAllUsers(); + const auto& profiles = profile_manager.GetAllUsers(); for (const auto& user : profiles) { Service::Account::ProfileBase profile{}; - if (!profile_manager->GetProfileBase(user, profile)) + if (!profile_manager.GetProfileBase(user, profile)) continue; const auto username = Common::StringFromFixedZeroTerminatedBuffer( @@ -167,11 +167,11 @@ void ConfigureProfileManager::PopulateUserList() { } void ConfigureProfileManager::UpdateCurrentUser() { - ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS); + ui->pm_add->setEnabled(profile_manager.GetUserCount() < Service::Account::MAX_USERS); - const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue()); + const auto& current_user = profile_manager.GetUser(Settings::values.current_user.GetValue()); ASSERT(current_user); - const auto username = GetAccountUsername(*profile_manager, *current_user); + const auto username = GetAccountUsername(profile_manager, *current_user); scene->clear(); scene->addPixmap( @@ -187,11 +187,11 @@ void ConfigureProfileManager::ApplyConfiguration() { void ConfigureProfileManager::SelectUser(const QModelIndex& index) { Settings::values.current_user = - std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager->GetUserCount() - 1)); + std::clamp<s32>(index.row(), 0, static_cast<s32>(profile_manager.GetUserCount() - 1)); UpdateCurrentUser(); - ui->pm_remove->setEnabled(profile_manager->GetUserCount() >= 2); + ui->pm_remove->setEnabled(profile_manager.GetUserCount() >= 2); ui->pm_rename->setEnabled(true); ui->pm_set_image->setEnabled(true); } @@ -204,18 +204,18 @@ void ConfigureProfileManager::AddUser() { } const auto uuid = Common::UUID::MakeRandom(); - profile_manager->CreateNewUser(uuid, username.toStdString()); + profile_manager.CreateNewUser(uuid, username.toStdString()); item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); } void ConfigureProfileManager::RenameUser() { const auto user = tree_view->currentIndex().row(); - const auto uuid = profile_manager->GetUser(user); + const auto uuid = profile_manager.GetUser(user); ASSERT(uuid); Service::Account::ProfileBase profile{}; - if (!profile_manager->GetProfileBase(*uuid, profile)) + if (!profile_manager.GetProfileBase(*uuid, profile)) return; const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:")); @@ -227,7 +227,7 @@ void ConfigureProfileManager::RenameUser() { std::fill(profile.username.begin(), profile.username.end(), '\0'); std::copy(username_std.begin(), username_std.end(), profile.username.begin()); - profile_manager->SetProfileBase(*uuid, profile); + profile_manager.SetProfileBase(*uuid, profile); item_model->setItem( user, 0, @@ -238,9 +238,9 @@ void ConfigureProfileManager::RenameUser() { void ConfigureProfileManager::ConfirmDeleteUser() { const auto index = tree_view->currentIndex().row(); - const auto uuid = profile_manager->GetUser(index); + const auto uuid = profile_manager.GetUser(index); ASSERT(uuid); - const auto username = GetAccountUsername(*profile_manager, *uuid); + const auto username = GetAccountUsername(profile_manager, *uuid); confirm_dialog->SetInfo(username, *uuid, [this, uuid]() { DeleteUser(*uuid); }); confirm_dialog->show(); @@ -252,7 +252,7 @@ void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) { } UpdateCurrentUser(); - if (!profile_manager->RemoveUser(uuid)) { + if (!profile_manager.RemoveUser(uuid)) { return; } @@ -265,7 +265,7 @@ void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) { void ConfigureProfileManager::SetUserImage() { const auto index = tree_view->currentIndex().row(); - const auto uuid = profile_manager->GetUser(index); + const auto uuid = profile_manager.GetUser(index); ASSERT(uuid); const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), @@ -317,7 +317,7 @@ void ConfigureProfileManager::SetUserImage() { } } - const auto username = GetAccountUsername(*profile_manager, *uuid); + const auto username = GetAccountUsername(profile_manager, *uuid); item_model->setItem(index, 0, new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)}); 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 { Q_OBJECT public: - explicit ConfigureProfileManager(const Core::System& system_, QWidget* parent = nullptr); + explicit ConfigureProfileManager(Core::System& system_, QWidget* parent = nullptr); ~ConfigureProfileManager() override; void ApplyConfiguration(); @@ -85,7 +85,6 @@ private: std::unique_ptr<Ui::ConfigureProfileManager> ui; bool enabled = false; - std::unique_ptr<Service::Account::ProfileManager> profile_manager; - + Service::Account::ProfileManager& profile_manager; const Core::System& system; }; 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 @@ #include "yuzu/debugger/wait_tree.h" #include "yuzu/uisettings.h" -#include "core/arm/arm_interface.h" +#include "core/arm/debug.h" #include "core/core.h" #include "core/hle/kernel/k_class_token.h" #include "core/hle/kernel/k_handle_table.h" @@ -129,7 +129,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons return list; } - auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(system, thread.GetContext64()); + auto backtrace = Core::GetBacktraceFromContext(thread.GetOwnerProcess(), thread.GetContext()); for (auto& entry : backtrace) { std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, @@ -238,10 +238,10 @@ QString WaitTreeThread::GetText() const { break; } - const auto& context = thread.GetContext64(); + const auto& context = thread.GetContext(); const QString pc_info = tr(" PC = 0x%1 LR = 0x%2") .arg(context.pc, 8, 16, QLatin1Char{'0'}) - .arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'}); + .arg(context.lr, 8, 16, QLatin1Char{'0'}); return QStringLiteral("%1%2 (%3) ") .arg(WaitTreeSynchronizationObject::GetText(), pc_info, status); } 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 SetDiscordEnabled(UISettings::values.enable_discord_presence.GetValue()); discord_rpc->Update(); - play_time_manager = std::make_unique<PlayTime::PlayTimeManager>(); + play_time_manager = std::make_unique<PlayTime::PlayTimeManager>(system->GetProfileManager()); system->GetRoomNetwork().Init(); @@ -526,8 +526,7 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk continue; } - const Service::Account::ProfileManager manager; - if (!manager.UserExistsIndex(selected_user)) { + if (!system->GetProfileManager().UserExistsIndex(selected_user)) { LOG_ERROR(Frontend, "Selected user doesn't exist"); continue; } @@ -691,7 +690,7 @@ void GMainWindow::ControllerSelectorRequestExit() { void GMainWindow::ProfileSelectorSelectProfile( const Core::Frontend::ProfileSelectParameters& parameters) { - profile_select_applet = new QtProfileSelectionDialog(system->HIDCore(), this, parameters); + profile_select_applet = new QtProfileSelectionDialog(*system, this, parameters); SCOPE_EXIT({ profile_select_applet->deleteLater(); profile_select_applet = nullptr; @@ -706,8 +705,8 @@ void GMainWindow::ProfileSelectorSelectProfile( return; } - const Service::Account::ProfileManager manager; - const auto uuid = manager.GetUser(static_cast<std::size_t>(profile_select_applet->GetIndex())); + const auto uuid = system->GetProfileManager().GetUser( + static_cast<std::size_t>(profile_select_applet->GetIndex())); if (!uuid.has_value()) { emit ProfileSelectorFinishedSelection(std::nullopt); return; @@ -1856,7 +1855,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p bool GMainWindow::SelectAndSetCurrentUser( const Core::Frontend::ProfileSelectParameters& parameters) { - QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters); + QtProfileSelectionDialog dialog(*system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -2271,7 +2270,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target .display_options = {}, .purpose = Service::AM::Applets::UserSelectionPurpose::General, }; - QtProfileSelectionDialog dialog(system->HIDCore(), this, parameters); + QtProfileSelectionDialog dialog(*system, this, parameters); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); dialog.setWindowModality(Qt::WindowModal); @@ -2288,8 +2287,8 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target return; } - Service::Account::ProfileManager manager; - const auto user_id = manager.GetUser(static_cast<std::size_t>(index)); + const auto user_id = + system->GetProfileManager().GetUser(static_cast<std::size_t>(index)); ASSERT(user_id); 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 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list, std::shared_ptr<Core::AnnounceMultiplayerSession> session, Core::System& system_) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), - ui(std::make_unique<Ui::Lobby>()), announce_multiplayer_session(session), - profile_manager(std::make_unique<Service::Account::ProfileManager>()), system{system_}, - room_network{system.GetRoomNetwork()} { + ui(std::make_unique<Ui::Lobby>()), + announce_multiplayer_session(session), system{system_}, room_network{ + system.GetRoomNetwork()} { ui->setupUi(this); // setup the watcher for background connections @@ -299,14 +299,15 @@ void Lobby::OnRefreshLobby() { } std::string Lobby::GetProfileUsername() { - const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue()); + const auto& current_user = + system.GetProfileManager().GetUser(Settings::values.current_user.GetValue()); Service::Account::ProfileBase profile{}; if (!current_user.has_value()) { return ""; } - if (!profile_manager->GetProfileBase(*current_user, profile)) { + if (!system.GetProfileManager().GetProfileBase(*current_user, profile)) { return ""; } 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 { class System; } -namespace Service::Account { -class ProfileManager; -} - /** * Listing of all public games pulled from services. The lobby should be simple enough for users to * find the game they want to play, and join it. @@ -103,7 +99,6 @@ private: QFutureWatcher<AnnounceMultiplayerRoom::RoomList> room_list_watcher; std::weak_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session; - std::unique_ptr<Service::Account::ProfileManager> profile_manager; QFutureWatcher<void>* watcher; Validation validation; 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 { PlayTime play_time; }; -std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() { - const Service::Account::ProfileManager manager; +std::optional<std::filesystem::path> GetCurrentUserPlayTimePath( + const Service::Account::ProfileManager& manager) { const auto uuid = manager.GetUser(static_cast<s32>(Settings::values.current_user)); if (!uuid.has_value()) { return std::nullopt; @@ -30,8 +30,9 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() { uuid->RawString().append(".bin"); } -[[nodiscard]] bool ReadPlayTimeFile(PlayTimeDatabase& out_play_time_db) { - const auto filename = GetCurrentUserPlayTimePath(); +[[nodiscard]] bool ReadPlayTimeFile(PlayTimeDatabase& out_play_time_db, + const Service::Account::ProfileManager& manager) { + const auto filename = GetCurrentUserPlayTimePath(manager); if (!filename.has_value()) { LOG_ERROR(Frontend, "Failed to get current user path"); @@ -66,8 +67,9 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() { return true; } -[[nodiscard]] bool WritePlayTimeFile(const PlayTimeDatabase& play_time_db) { - const auto filename = GetCurrentUserPlayTimePath(); +[[nodiscard]] bool WritePlayTimeFile(const PlayTimeDatabase& play_time_db, + const Service::Account::ProfileManager& manager) { + const auto filename = GetCurrentUserPlayTimePath(manager); if (!filename.has_value()) { LOG_ERROR(Frontend, "Failed to get current user path"); @@ -96,8 +98,9 @@ std::optional<std::filesystem::path> GetCurrentUserPlayTimePath() { } // namespace -PlayTimeManager::PlayTimeManager() { - if (!ReadPlayTimeFile(database)) { +PlayTimeManager::PlayTimeManager(Service::Account::ProfileManager& profile_manager) + : manager{profile_manager} { + if (!ReadPlayTimeFile(database, manager)) { LOG_ERROR(Frontend, "Failed to read play time database! Resetting to default."); } } @@ -142,7 +145,7 @@ void PlayTimeManager::AutoTimestamp(std::stop_token stop_token) { } void PlayTimeManager::Save() { - if (!WritePlayTimeFile(database)) { + if (!WritePlayTimeFile(database, manager)) { LOG_ERROR(Frontend, "Failed to update play time database!"); } } 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 @@ #include "common/common_types.h" #include "common/polyfill_thread.h" +namespace Service::Account { +class ProfileManager; +} + namespace PlayTime { using ProgramId = u64; @@ -19,7 +23,7 @@ using PlayTimeDatabase = std::map<ProgramId, PlayTime>; class PlayTimeManager { public: - explicit PlayTimeManager(); + explicit PlayTimeManager(Service::Account::ProfileManager& profile_manager); ~PlayTimeManager(); YUZU_NON_COPYABLE(PlayTimeManager); @@ -32,11 +36,13 @@ public: void Stop(); private: + void AutoTimestamp(std::stop_token stop_token); + void Save(); + PlayTimeDatabase database; u64 running_program_id; std::jthread play_time_thread; - void AutoTimestamp(std::stop_token stop_token); - void Save(); + Service::Account::ProfileManager& manager; }; QString ReadablePlayTime(qulonglong time_seconds); diff --git a/vcpkg.json b/vcpkg.json index da4e9edb9..01a4657d4 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", "name": "yuzu", - "builtin-baseline": "cbf56573a987527b39272e88cbdd11389b78c6e4", + "builtin-baseline": "a42af01b72c28a8e1d7b48107b33e4f286a55ef6", "version": "1.0", "dependencies": [ "boost-algorithm", @@ -50,7 +50,7 @@ }, { "name": "fmt", - "version": "10.0.0" + "version": "10.1.1" } ] } |