diff options
88 files changed, 6779 insertions, 1491 deletions
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/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index 5721327e7..f763c657e 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -174,7 +174,8 @@ android { "-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work "-DYUZU_USE_BUNDLED_VCPKG=ON", "-DYUZU_USE_BUNDLED_FFMPEG=ON", - "-DYUZU_ENABLE_LTO=ON" + "-DYUZU_ENABLE_LTO=ON", + "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON" ) abiFilters("arm64-v8a", "x86_64") diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 47d028d48..ba3081efb 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -123,6 +123,12 @@ namespace Common { return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24; } +[[nodiscard]] constexpr u64 MakeMagic(char a, char b, char c, char d, char e, char f, char g, + char h) { + return u64(a) << 0 | u64(b) << 8 | u64(c) << 16 | u64(d) << 24 | u64(e) << 32 | u64(f) << 40 | + u64(g) << 48 | u64(h) << 56; +} + // std::size() does not support zero-size C arrays. We're fixing that. template <class C> constexpr auto Size(const C& c) -> decltype(c.size()) { diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index c3a81f9a9..d2f50432a 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -354,18 +354,36 @@ std::string_view RemoveTrailingSlash(std::string_view path) { return path; } -std::vector<std::string> SplitPathComponents(std::string_view filename) { - std::string copy(filename); - std::replace(copy.begin(), copy.end(), '\\', '/'); - std::vector<std::string> out; - - std::stringstream stream(copy); - std::string item; - while (std::getline(stream, item, '/')) { - out.push_back(std::move(item)); +template <typename F> +static void ForEachPathComponent(std::string_view filename, F&& cb) { + const char* component_begin = filename.data(); + const char* const end = component_begin + filename.size(); + for (const char* it = component_begin; it != end; ++it) { + const char c = *it; + if (c == '\\' || c == '/') { + if (component_begin != it) { + cb(std::string_view{component_begin, it}); + } + component_begin = it + 1; + } } + if (component_begin != end) { + cb(std::string_view{component_begin, end}); + } +} + +std::vector<std::string_view> SplitPathComponents(std::string_view filename) { + std::vector<std::string_view> components; + ForEachPathComponent(filename, [&](auto component) { components.emplace_back(component); }); + + return components; +} + +std::vector<std::string> SplitPathComponentsCopy(std::string_view filename) { + std::vector<std::string> components; + ForEachPathComponent(filename, [&](auto component) { components.emplace_back(component); }); - return out; + return components; } std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) { diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index 2874ea738..23c8b1359 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h @@ -289,7 +289,11 @@ enum class DirectorySeparator { // Splits the path on '/' or '\' and put the components into a vector // i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" } -[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename); +[[nodiscard]] std::vector<std::string_view> SplitPathComponents(std::string_view filename); + +// Splits the path on '/' or '\' and put the components into a vector +// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" } +[[nodiscard]] std::vector<std::string> SplitPathComponentsCopy(std::string_view filename); // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\' // depending if directory_separator is BackwardSlash or PlatformDefault and running on windows 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/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7b9ed856f..96ab39cb8 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -549,6 +549,11 @@ 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 @@ -569,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 @@ -784,6 +790,12 @@ add_library(core STATIC hle/service/service.h hle/service/set/set.cpp hle/service/set/set.h + hle/service/set/appln_settings.cpp + hle/service/set/appln_settings.h + hle/service/set/device_settings.cpp + hle/service/set/device_settings.h + hle/service/set/private_settings.cpp + hle/service/set/private_settings.h hle/service/set/set_cal.cpp hle/service/set/set_cal.h hle/service/set/set_fd.cpp @@ -792,6 +804,8 @@ add_library(core STATIC hle/service/set/set_sys.h hle/service/set/settings.cpp hle/service/set/settings.h + hle/service/set/system_settings.cpp + hle/service/set/system_settings.h hle/service/sm/sm.cpp hle/service/sm/sm.h hle/service/sm/sm_controller.cpp @@ -947,15 +961,19 @@ if (HAS_NCE) set(CMAKE_ASM_FLAGS "${CFLAGS} -x assembler-with-cpp") target_sources(core PRIVATE + arm/nce/arm_nce_asm_definitions.h arm/nce/arm_nce.cpp arm/nce/arm_nce.h arm/nce/arm_nce.s arm/nce/guest_context.h + arm/nce/instructions.h + arm/nce/interpreter_visitor.cpp + arm/nce/interpreter_visitor.h arm/nce/patcher.cpp arm/nce/patcher.h - arm/nce/instructions.h + arm/nce/visitor_base.h ) - target_link_libraries(core PRIVATE merry::oaknut) + target_link_libraries(core PRIVATE merry::mcl merry::oaknut) endif() if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) diff --git a/src/core/arm/nce/arm_nce.cpp b/src/core/arm/nce/arm_nce.cpp index b42a32a0b..1311e66a9 100644 --- a/src/core/arm/nce/arm_nce.cpp +++ b/src/core/arm/nce/arm_nce.cpp @@ -6,7 +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/interpreter_visitor.h" #include "core/arm/nce/patcher.h" #include "core/core.h" #include "core/memory.h" @@ -21,7 +21,8 @@ namespace Core { namespace { -struct sigaction g_orig_action; +struct sigaction g_orig_bus_action; +struct sigaction g_orig_segv_action; // Verify assembly offsets. using NativeExecutionParameters = Kernel::KThread::NativeExecutionParameters; @@ -37,6 +38,9 @@ fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) { return reinterpret_cast<fpsimd_context*>(header); } +using namespace Common::Literals; +constexpr u32 StackSize = 32_KiB; + } // namespace void* ArmNce::RestoreGuestContext(void* raw_context) { @@ -104,19 +108,10 @@ void ArmNce::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) { host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0); } -bool ArmNce::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { +bool ArmNce::HandleFailedGuestFault(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); - // Try to handle an invalid access. - // TODO: handle accesses which split a page? - const Common::ProcessAddress addr = - (reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK); - if (guest_ctx->system->ApplicationMemory().InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) { - // We handled the access successfully and are returning to guest code. - return true; - } - // We can't handle the access, so determine why we crashed. const bool is_prefetch_abort = host_ctx.pc == reinterpret_cast<u64>(info->si_addr); @@ -143,8 +138,44 @@ bool ArmNce::HandleGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw return false; } -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); +bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { + auto& host_ctx = static_cast<ucontext_t*>(raw_context)->uc_mcontext; + auto* fpctx = GetFloatingPointState(host_ctx); + auto& memory = guest_ctx->system->ApplicationMemory(); + + // Match and execute an instruction. + auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx, fpctx); + if (next_pc) { + host_ctx.pc = *next_pc; + return true; + } + + // We couldn't handle the access. + return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); +} + +bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { + auto* info = static_cast<siginfo_t*>(raw_info); + + // Try to handle an invalid access. + // TODO: handle accesses which split a page? + const Common::ProcessAddress addr = + (reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK); + if (guest_ctx->system->ApplicationMemory().InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) { + // We handled the access successfully and are returning to guest code. + return true; + } + + // We couldn't handle the access. + return HandleFailedGuestFault(guest_ctx, raw_info, raw_context); +} + +void ArmNce::HandleHostAlignmentFault(int sig, void* raw_info, void* raw_context) { + return g_orig_bus_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context); +} + +void ArmNce::HandleHostAccessFault(int sig, void* raw_info, void* raw_context) { + return g_orig_segv_action.sa_sigaction(sig, static_cast<siginfo_t*>(raw_info), raw_context); } void ArmNce::LockThread(Kernel::KThread* thread) { @@ -225,18 +256,31 @@ ArmNce::ArmNce(System& system, bool uses_wall_clock, std::size_t core_index) ArmNce::~ArmNce() = default; void ArmNce::Initialize() { - m_thread_id = gettid(); + if (m_thread_id == -1) { + m_thread_id = gettid(); + } + + // Configure signal stack. + if (!m_stack) { + m_stack = std::make_unique<u8[]>(StackSize); + + stack_t ss{}; + ss.ss_sp = m_stack.get(); + ss.ss_size = StackSize; + sigaltstack(&ss, nullptr); + } - // Setup our signals - static std::once_flag signals; - std::call_once(signals, [] { + // Set up signals. + static std::once_flag flag; + std::call_once(flag, [] { using HandlerType = decltype(sigaction::sa_sigaction); sigset_t signal_mask; sigemptyset(&signal_mask); sigaddset(&signal_mask, ReturnToRunCodeByExceptionLevelChangeSignal); sigaddset(&signal_mask, BreakFromRunCodeSignal); - sigaddset(&signal_mask, GuestFaultSignal); + sigaddset(&signal_mask, GuestAlignmentFaultSignal); + sigaddset(&signal_mask, GuestAccessFaultSignal); struct sigaction return_to_run_code_action {}; return_to_run_code_action.sa_flags = SA_SIGINFO | SA_ONSTACK; @@ -253,18 +297,19 @@ void ArmNce::Initialize() { 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>(&ArmNce::GuestFaultSignalHandler); - fault_action.sa_mask = signal_mask; - Common::SigAction(GuestFaultSignal, &fault_action, &g_orig_action); - - // Simplify call for g_orig_action. - // These fields occupy the same space in memory, so this should be a no-op in practice. - if (!(g_orig_action.sa_flags & SA_SIGINFO)) { - g_orig_action.sa_sigaction = - reinterpret_cast<decltype(g_orig_action.sa_sigaction)>(g_orig_action.sa_handler); - } + struct sigaction alignment_fault_action {}; + alignment_fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK; + alignment_fault_action.sa_sigaction = + reinterpret_cast<HandlerType>(&ArmNce::GuestAlignmentFaultSignalHandler); + alignment_fault_action.sa_mask = signal_mask; + Common::SigAction(GuestAlignmentFaultSignal, &alignment_fault_action, nullptr); + + struct sigaction access_fault_action {}; + access_fault_action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART; + access_fault_action.sa_sigaction = + reinterpret_cast<HandlerType>(&ArmNce::GuestAccessFaultSignalHandler); + access_fault_action.sa_mask = signal_mask; + Common::SigAction(GuestAccessFaultSignal, &access_fault_action, &g_orig_segv_action); }); } diff --git a/src/core/arm/nce/arm_nce.h b/src/core/arm/nce/arm_nce.h index f55c10d1d..be9b304c4 100644 --- a/src/core/arm/nce/arm_nce.h +++ b/src/core/arm/nce/arm_nce.h @@ -61,7 +61,8 @@ private: static void ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info, void* raw_context); static void BreakFromRunCodeSignalHandler(int sig, void* info, void* raw_context); - static void GuestFaultSignalHandler(int sig, void* info, void* raw_context); + static void GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context); + static void GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context); static void LockThreadParameters(void* tpidr); static void UnlockThreadParameters(void* tpidr); @@ -70,8 +71,11 @@ private: // C++ implementation functions for assembly definitions. static void* RestoreGuestContext(void* raw_context); static void SaveGuestContext(GuestContext* ctx, void* raw_context); - static bool HandleGuestFault(GuestContext* ctx, void* info, void* raw_context); - static void HandleHostFault(int sig, void* info, void* raw_context); + static bool HandleFailedGuestFault(GuestContext* ctx, void* info, void* raw_context); + static bool HandleGuestAlignmentFault(GuestContext* ctx, void* info, void* raw_context); + static bool HandleGuestAccessFault(GuestContext* ctx, void* info, void* raw_context); + static void HandleHostAlignmentFault(int sig, void* info, void* raw_context); + static void HandleHostAccessFault(int sig, void* info, void* raw_context); public: Core::System& m_system; @@ -83,6 +87,9 @@ public: // Core context. GuestContext m_guest_ctx{}; Kernel::KThread* m_running_thread{}; + + // Stack for signal processing. + std::unique_ptr<u8[]> m_stack{}; }; } // namespace Core diff --git a/src/core/arm/nce/arm_nce.s b/src/core/arm/nce/arm_nce.s index 4aeda4740..c68c05949 100644 --- a/src/core/arm/nce/arm_nce.s +++ b/src/core/arm/nce/arm_nce.s @@ -130,11 +130,11 @@ _ZN4Core6ArmNce29BreakFromRunCodeSignalHandlerEiPvS1_: ret -/* static void Core::ArmNce::GuestFaultSignalHandler(int sig, void* info, void* raw_context) */ -.section .text._ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, "ax", %progbits -.global _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_ -.type _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_, %function -_ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_: +/* static void Core::ArmNce::GuestAlignmentFaultSignalHandler(int sig, void* info, void* raw_context) */ +.section .text._ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_, "ax", %progbits +.global _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_ +.type _ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_, %function +_ZN4Core6ArmNce32GuestAlignmentFaultSignalHandlerEiPvS1_: /* Check to see if we have the correct TLS magic. */ mrs x8, tpidr_el0 ldr w9, [x8, #(TpidrEl0TlsMagic)] @@ -146,7 +146,7 @@ _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_: /* Incorrect TLS magic, so this is a host fault. */ /* Tail call the handler. */ - b _ZN4Core6ArmNce15HandleHostFaultEiPvS1_ + b _ZN4Core6ArmNce24HandleHostAlignmentFaultEiPvS1_ 1: /* Correct TLS magic, so this is a guest fault. */ @@ -163,7 +163,53 @@ _ZN4Core6ArmNce23GuestFaultSignalHandlerEiPvS1_: msr tpidr_el0, x3 /* Call the handler. */ - bl _ZN4Core6ArmNce16HandleGuestFaultEPNS_12GuestContextEPvS3_ + bl _ZN4Core6ArmNce25HandleGuestAlignmentFaultEPNS_12GuestContextEPvS3_ + + /* If the handler returned false, we want to preserve the host tpidr_el0. */ + cbz x0, 2f + + /* Otherwise, restore guest tpidr_el0. */ + msr tpidr_el0, x19 + +2: + ldr x19, [sp, #0x10] + ldp x29, x30, [sp], #0x20 + ret + +/* static void Core::ArmNce::GuestAccessFaultSignalHandler(int sig, void* info, void* raw_context) */ +.section .text._ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_, "ax", %progbits +.global _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_ +.type _ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_, %function +_ZN4Core6ArmNce29GuestAccessFaultSignalHandlerEiPvS1_: + /* Check to see if we have the correct TLS magic. */ + mrs x8, tpidr_el0 + ldr w9, [x8, #(TpidrEl0TlsMagic)] + + LOAD_IMMEDIATE_32(w10, TlsMagic) + + cmp w9, w10 + b.eq 1f + + /* Incorrect TLS magic, so this is a host fault. */ + /* Tail call the handler. */ + b _ZN4Core6ArmNce21HandleHostAccessFaultEiPvS1_ + +1: + /* Correct TLS magic, so this is a guest fault. */ + stp x29, x30, [sp, #-0x20]! + str x19, [sp, #0x10] + mov x29, sp + + /* Save the old tpidr_el0. */ + mov x19, x8 + + /* Restore host tpidr_el0. */ + ldr x0, [x8, #(TpidrEl0NativeContext)] + ldr x3, [x0, #(GuestContextHostContext + HostContextTpidrEl0)] + msr tpidr_el0, x3 + + /* Call the handler. */ + bl _ZN4Core6ArmNce22HandleGuestAccessFaultEPNS_12GuestContextEPvS3_ /* If the handler returned false, we want to preserve the host tpidr_el0. */ cbz x0, 2f diff --git a/src/core/arm/nce/arm_nce_asm_definitions.h b/src/core/arm/nce/arm_nce_asm_definitions.h index 8a9b285b5..8ea4383f7 100644 --- a/src/core/arm/nce/arm_nce_asm_definitions.h +++ b/src/core/arm/nce/arm_nce_asm_definitions.h @@ -10,7 +10,8 @@ #define ReturnToRunCodeByExceptionLevelChangeSignal SIGUSR2 #define BreakFromRunCodeSignal SIGURG -#define GuestFaultSignal SIGSEGV +#define GuestAccessFaultSignal SIGSEGV +#define GuestAlignmentFaultSignal SIGBUS #define GuestContextSp 0xF8 #define GuestContextHostContext 0x320 diff --git a/src/core/arm/nce/interpreter_visitor.cpp b/src/core/arm/nce/interpreter_visitor.cpp new file mode 100644 index 000000000..8e81c66a5 --- /dev/null +++ b/src/core/arm/nce/interpreter_visitor.cpp @@ -0,0 +1,825 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2023 merryhime <https://mary.rs> +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/bit_cast.h" +#include "core/arm/nce/interpreter_visitor.h" + +#include <dynarmic/frontend/A64/decoder/a64.h> + +namespace Core { + +template <u32 BitSize> +u64 SignExtendToLong(u64 value) { + u64 mask = 1ULL << (BitSize - 1); + value &= (1ULL << BitSize) - 1; + return (value ^ mask) - mask; +} + +static u64 SignExtendToLong(u64 value, u64 bitsize) { + switch (bitsize) { + case 8: + return SignExtendToLong<8>(value); + case 16: + return SignExtendToLong<16>(value); + case 32: + return SignExtendToLong<32>(value); + default: + return value; + } +} + +template <u64 BitSize> +u32 SignExtendToWord(u32 value) { + u32 mask = 1ULL << (BitSize - 1); + value &= (1ULL << BitSize) - 1; + return (value ^ mask) - mask; +} + +static u32 SignExtendToWord(u32 value, u64 bitsize) { + switch (bitsize) { + case 8: + return SignExtendToWord<8>(value); + case 16: + return SignExtendToWord<16>(value); + default: + return value; + } +} + +static u64 SignExtend(u64 value, u64 bitsize, u64 regsize) { + if (regsize == 64) { + return SignExtendToLong(value, bitsize); + } else { + return SignExtendToWord(static_cast<u32>(value), bitsize); + } +} + +static u128 VectorGetElement(u128 value, u64 bitsize) { + switch (bitsize) { + case 8: + return {value[0] & ((1ULL << 8) - 1), 0}; + case 16: + return {value[0] & ((1ULL << 16) - 1), 0}; + case 32: + return {value[0] & ((1ULL << 32) - 1), 0}; + case 64: + return {value[0], 0}; + default: + return value; + } +} + +u64 InterpreterVisitor::ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift) { + ASSERT(shift <= 4); + ASSERT(bitsize == 32 || bitsize == 64); + u64 val = this->GetReg(reg); + size_t len; + u64 extended; + bool signed_extend; + + switch (option.ZeroExtend()) { + case 0b000: { // UXTB + val &= ((1ULL << 8) - 1); + len = 8; + signed_extend = false; + break; + } + case 0b001: { // UXTH + val &= ((1ULL << 16) - 1); + len = 16; + signed_extend = false; + break; + } + case 0b010: { // UXTW + val &= ((1ULL << 32) - 1); + len = 32; + signed_extend = false; + break; + } + case 0b011: { // UXTX + len = 64; + signed_extend = false; + break; + } + case 0b100: { // SXTB + val &= ((1ULL << 8) - 1); + len = 8; + signed_extend = true; + break; + } + case 0b101: { // SXTH + val &= ((1ULL << 16) - 1); + len = 16; + signed_extend = true; + break; + } + case 0b110: { // SXTW + val &= ((1ULL << 32) - 1); + len = 32; + signed_extend = true; + break; + } + case 0b111: { // SXTX + len = 64; + signed_extend = true; + break; + } + default: + UNREACHABLE(); + } + + if (len < bitsize && signed_extend) { + extended = SignExtend(val, len, bitsize); + } else { + extended = val; + } + + return extended << shift; +} + +u128 InterpreterVisitor::GetVec(Vec v) { + return m_fpsimd_regs[static_cast<u32>(v)]; +} + +u64 InterpreterVisitor::GetReg(Reg r) { + return m_regs[static_cast<u32>(r)]; +} + +u64 InterpreterVisitor::GetSp() { + return m_sp; +} + +u64 InterpreterVisitor::GetPc() { + return m_pc; +} + +void InterpreterVisitor::SetVec(Vec v, u128 value) { + m_fpsimd_regs[static_cast<u32>(v)] = value; +} + +void InterpreterVisitor::SetReg(Reg r, u64 value) { + m_regs[static_cast<u32>(r)] = value; +} + +void InterpreterVisitor::SetSp(u64 value) { + m_sp = value; +} + +bool InterpreterVisitor::Ordered(size_t size, bool L, bool o0, Reg Rn, Reg Rt) { + const auto memop = L ? MemOp::Load : MemOp::Store; + const size_t elsize = 8 << size; + const size_t datasize = elsize; + + // Operation + const size_t dbytes = datasize / 8; + + u64 address; + if (Rn == Reg::SP) { + address = this->GetSp(); + } else { + address = this->GetReg(Rn); + } + + switch (memop) { + case MemOp::Store: { + std::atomic_thread_fence(std::memory_order_seq_cst); + u64 value = this->GetReg(Rt); + m_memory.WriteBlock(address, &value, dbytes); + std::atomic_thread_fence(std::memory_order_seq_cst); + break; + } + case MemOp::Load: { + u64 value = 0; + m_memory.ReadBlock(address, &value, dbytes); + this->SetReg(Rt, value); + std::atomic_thread_fence(std::memory_order_seq_cst); + break; + } + default: + UNREACHABLE(); + } + + return true; +} + +bool InterpreterVisitor::STLLR(Imm<2> sz, Reg Rn, Reg Rt) { + const size_t size = sz.ZeroExtend<size_t>(); + const bool L = 0; + const bool o0 = 0; + return this->Ordered(size, L, o0, Rn, Rt); +} + +bool InterpreterVisitor::STLR(Imm<2> sz, Reg Rn, Reg Rt) { + const size_t size = sz.ZeroExtend<size_t>(); + const bool L = 0; + const bool o0 = 1; + return this->Ordered(size, L, o0, Rn, Rt); +} + +bool InterpreterVisitor::LDLAR(Imm<2> sz, Reg Rn, Reg Rt) { + const size_t size = sz.ZeroExtend<size_t>(); + const bool L = 1; + const bool o0 = 0; + return this->Ordered(size, L, o0, Rn, Rt); +} + +bool InterpreterVisitor::LDAR(Imm<2> sz, Reg Rn, Reg Rt) { + const size_t size = sz.ZeroExtend<size_t>(); + const bool L = 1; + const bool o0 = 1; + return this->Ordered(size, L, o0, Rn, Rt); +} + +bool InterpreterVisitor::LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) { + const size_t size = opc_0 == 0 ? 4 : 8; + const s64 offset = Dynarmic::concatenate(imm19, Imm<2>{0}).SignExtend<s64>(); + const u64 address = this->GetPc() + offset; + + u64 data = 0; + m_memory.ReadBlock(address, &data, size); + + this->SetReg(Rt, data); + return true; +} + +bool InterpreterVisitor::LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) { + if (opc == 0b11) { + // Unallocated encoding + return false; + } + + const u64 size = 4 << opc.ZeroExtend(); + const u64 offset = imm19.SignExtend<u64>() << 2; + const u64 address = this->GetPc() + offset; + + u128 data{}; + m_memory.ReadBlock(address, &data, size); + this->SetVec(Vt, data); + return true; +} + +bool InterpreterVisitor::STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, + Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt) { + if ((L == 0 && opc.Bit<0>() == 1) || opc == 0b11) { + // Unallocated encoding + return false; + } + + const auto memop = L == 1 ? MemOp::Load : MemOp::Store; + if (memop == MemOp::Load && wback && (Rt == Rn || Rt2 == Rn) && Rn != Reg::R31) { + // Unpredictable instruction + return false; + } + if (memop == MemOp::Store && wback && (Rt == Rn || Rt2 == Rn) && Rn != Reg::R31) { + // Unpredictable instruction + return false; + } + if (memop == MemOp::Load && Rt == Rt2) { + // Unpredictable instruction + return false; + } + + u64 address; + if (Rn == Reg::SP) { + address = this->GetSp(); + } else { + address = this->GetReg(Rn); + } + + const bool postindex = !not_postindex; + const bool signed_ = opc.Bit<0>() != 0; + const size_t scale = 2 + opc.Bit<1>(); + const size_t datasize = 8 << scale; + const u64 offset = imm7.SignExtend<u64>() << scale; + + if (!postindex) { + address += offset; + } + + const size_t dbytes = datasize / 8; + switch (memop) { + case MemOp::Store: { + u64 data1 = this->GetReg(Rt); + u64 data2 = this->GetReg(Rt2); + m_memory.WriteBlock(address, &data1, dbytes); + m_memory.WriteBlock(address + dbytes, &data2, dbytes); + break; + } + case MemOp::Load: { + u64 data1 = 0, data2 = 0; + m_memory.ReadBlock(address, &data1, dbytes); + m_memory.ReadBlock(address + dbytes, &data2, dbytes); + if (signed_) { + this->SetReg(Rt, SignExtend(data1, datasize, 64)); + this->SetReg(Rt2, SignExtend(data2, datasize, 64)); + } else { + this->SetReg(Rt, data1); + this->SetReg(Rt2, data2); + } + break; + } + default: + UNREACHABLE(); + } + + if (wback) { + if (postindex) { + address += offset; + } + + if (Rn == Reg::SP) { + this->SetSp(address); + } else { + this->SetReg(Rn, address); + } + } + + return true; +} + +bool InterpreterVisitor::STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, + Imm<7> imm7, Vec Vt2, Reg Rn, Vec Vt) { + if (opc == 0b11) { + // Unallocated encoding + return false; + } + + const auto memop = L == 1 ? MemOp::Load : MemOp::Store; + if (memop == MemOp::Load && Vt == Vt2) { + // Unpredictable instruction + return false; + } + + u64 address; + if (Rn == Reg::SP) { + address = this->GetSp(); + } else { + address = this->GetReg(Rn); + } + + const bool postindex = !not_postindex; + const size_t scale = 2 + opc.ZeroExtend<size_t>(); + const size_t datasize = 8 << scale; + const u64 offset = imm7.SignExtend<u64>() << scale; + const size_t dbytes = datasize / 8; + + if (!postindex) { + address += offset; + } + + switch (memop) { + case MemOp::Store: { + u128 data1 = VectorGetElement(this->GetVec(Vt), datasize); + u128 data2 = VectorGetElement(this->GetVec(Vt2), datasize); + m_memory.WriteBlock(address, &data1, dbytes); + m_memory.WriteBlock(address + dbytes, &data2, dbytes); + break; + } + case MemOp::Load: { + u128 data1{}, data2{}; + m_memory.ReadBlock(address, &data1, dbytes); + m_memory.ReadBlock(address + dbytes, &data2, dbytes); + this->SetVec(Vt, data1); + this->SetVec(Vt2, data2); + break; + } + default: + UNREACHABLE(); + } + + if (wback) { + if (postindex) { + address += offset; + } + + if (Rn == Reg::SP) { + this->SetSp(address); + } else { + this->SetReg(Rn, address); + } + } + + return true; +} + +bool InterpreterVisitor::RegisterImmediate(bool wback, bool postindex, size_t scale, u64 offset, + Imm<2> size, Imm<2> opc, Reg Rn, Reg Rt) { + MemOp memop; + bool signed_ = false; + size_t regsize = 0; + + if (opc.Bit<1>() == 0) { + memop = opc.Bit<0>() ? MemOp::Load : MemOp::Store; + regsize = size == 0b11 ? 64 : 32; + signed_ = false; + } else if (size == 0b11) { + memop = MemOp::Prefetch; + ASSERT(!opc.Bit<0>()); + } else { + memop = MemOp::Load; + ASSERT(!(size == 0b10 && opc.Bit<0>() == 1)); + regsize = opc.Bit<0>() ? 32 : 64; + signed_ = true; + } + + if (memop == MemOp::Load && wback && Rn == Rt && Rn != Reg::R31) { + // Unpredictable instruction + return false; + } + if (memop == MemOp::Store && wback && Rn == Rt && Rn != Reg::R31) { + // Unpredictable instruction + return false; + } + + u64 address; + if (Rn == Reg::SP) { + address = this->GetSp(); + } else { + address = this->GetReg(Rn); + } + if (!postindex) { + address += offset; + } + + const size_t datasize = 8 << scale; + switch (memop) { + case MemOp::Store: { + u64 data = this->GetReg(Rt); + m_memory.WriteBlock(address, &data, datasize / 8); + break; + } + case MemOp::Load: { + u64 data = 0; + m_memory.ReadBlock(address, &data, datasize / 8); + if (signed_) { + this->SetReg(Rt, SignExtend(data, datasize, regsize)); + } else { + this->SetReg(Rt, data); + } + break; + } + case MemOp::Prefetch: + // this->Prefetch(address, Rt) + break; + } + + if (wback) { + if (postindex) { + address += offset; + } + + if (Rn == Reg::SP) { + this->SetSp(address); + } else { + this->SetReg(Rn, address); + } + } + + return true; +} + +bool InterpreterVisitor::STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, + Reg Rn, Reg Rt) { + const bool wback = true; + const bool postindex = !not_postindex; + const size_t scale = size.ZeroExtend<size_t>(); + const u64 offset = imm9.SignExtend<u64>(); + + return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt); +} + +bool InterpreterVisitor::STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) { + const bool wback = false; + const bool postindex = false; + const size_t scale = size.ZeroExtend<size_t>(); + const u64 offset = imm12.ZeroExtend<u64>() << scale; + + return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt); +} + +bool InterpreterVisitor::STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) { + const bool wback = false; + const bool postindex = false; + const size_t scale = size.ZeroExtend<size_t>(); + const u64 offset = imm9.SignExtend<u64>(); + + return this->RegisterImmediate(wback, postindex, scale, offset, size, opc, Rn, Rt); +} + +bool InterpreterVisitor::SIMDImmediate(bool wback, bool postindex, size_t scale, u64 offset, + MemOp memop, Reg Rn, Vec Vt) { + const size_t datasize = 8 << scale; + + u64 address; + if (Rn == Reg::SP) { + address = this->GetSp(); + } else { + address = this->GetReg(Rn); + } + + if (!postindex) { + address += offset; + } + + switch (memop) { + case MemOp::Store: { + u128 data = VectorGetElement(this->GetVec(Vt), datasize); + m_memory.WriteBlock(address, &data, datasize / 8); + break; + } + case MemOp::Load: { + u128 data{}; + m_memory.ReadBlock(address, &data, datasize); + this->SetVec(Vt, data); + break; + } + default: + UNREACHABLE(); + } + + if (wback) { + if (postindex) { + address += offset; + } + + if (Rn == Reg::SP) { + this->SetSp(address); + } else { + this->SetReg(Rn, address); + } + } + + return true; +} + +bool InterpreterVisitor::STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, + bool not_postindex, Reg Rn, Vec Vt) { + const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>(); + if (scale > 4) { + // Unallocated encoding + return false; + } + + const bool wback = true; + const bool postindex = !not_postindex; + const u64 offset = imm9.SignExtend<u64>(); + + return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt); +} + +bool InterpreterVisitor::STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, + Vec Vt) { + const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>(); + if (scale > 4) { + // Unallocated encoding + return false; + } + + const bool wback = false; + const bool postindex = false; + const u64 offset = imm12.ZeroExtend<u64>() << scale; + + return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt); +} + +bool InterpreterVisitor::LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, + bool not_postindex, Reg Rn, Vec Vt) { + const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>(); + if (scale > 4) { + // Unallocated encoding + return false; + } + + const bool wback = true; + const bool postindex = !not_postindex; + const u64 offset = imm9.SignExtend<u64>(); + + return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt); +} + +bool InterpreterVisitor::LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, + Vec Vt) { + const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>(); + if (scale > 4) { + // Unallocated encoding + return false; + } + + const bool wback = false; + const bool postindex = false; + const u64 offset = imm12.ZeroExtend<u64>() << scale; + + return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt); +} + +bool InterpreterVisitor::STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) { + const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>(); + if (scale > 4) { + // Unallocated encoding + return false; + } + + const bool wback = false; + const bool postindex = false; + const u64 offset = imm9.SignExtend<u64>(); + + return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Store, Rn, Vt); +} + +bool InterpreterVisitor::LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) { + const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>(); + if (scale > 4) { + // Unallocated encoding + return false; + } + + const bool wback = false; + const bool postindex = false; + const u64 offset = imm9.SignExtend<u64>(); + + return this->SIMDImmediate(wback, postindex, scale, offset, MemOp::Load, Rn, Vt); +} + +bool InterpreterVisitor::RegisterOffset(size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1, + Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Reg Rt) { + MemOp memop; + size_t regsize = 64; + bool signed_ = false; + + if (opc_1 == 0) { + memop = opc_0 == 1 ? MemOp::Load : MemOp::Store; + regsize = size == 0b11 ? 64 : 32; + signed_ = false; + } else if (size == 0b11) { + memop = MemOp::Prefetch; + if (opc_0 == 1) { + // Unallocated encoding + return false; + } + } else { + memop = MemOp::Load; + if (size == 0b10 && opc_0 == 1) { + // Unallocated encoding + return false; + } + regsize = opc_0 == 1 ? 32 : 64; + signed_ = true; + } + + const size_t datasize = 8 << scale; + + // Operation + const u64 offset = this->ExtendReg(64, Rm, option, shift); + + u64 address; + if (Rn == Reg::SP) { + address = this->GetSp(); + } else { + address = this->GetReg(Rn); + } + address += offset; + + switch (memop) { + case MemOp::Store: { + u64 data = this->GetReg(Rt); + m_memory.WriteBlock(address, &data, datasize / 8); + break; + } + case MemOp::Load: { + u64 data = 0; + m_memory.ReadBlock(address, &data, datasize / 8); + if (signed_) { + this->SetReg(Rt, SignExtend(data, datasize, regsize)); + } else { + this->SetReg(Rt, data); + } + break; + } + case MemOp::Prefetch: + break; + } + + return true; +} + +bool InterpreterVisitor::STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Reg Rt) { + const Imm<1> opc_0{0}; + const size_t scale = size.ZeroExtend<size_t>(); + const u8 shift = S ? static_cast<u8>(scale) : 0; + if (!option.Bit<1>()) { + // Unallocated encoding + return false; + } + return this->RegisterOffset(scale, shift, size, opc_1, opc_0, Rm, option, Rn, Rt); +} + +bool InterpreterVisitor::LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Reg Rt) { + const Imm<1> opc_0{1}; + const size_t scale = size.ZeroExtend<size_t>(); + const u8 shift = S ? static_cast<u8>(scale) : 0; + if (!option.Bit<1>()) { + // Unallocated encoding + return false; + } + return this->RegisterOffset(scale, shift, size, opc_1, opc_0, Rm, option, Rn, Rt); +} + +bool InterpreterVisitor::SIMDOffset(size_t scale, u8 shift, Imm<1> opc_0, Reg Rm, Imm<3> option, + Reg Rn, Vec Vt) { + const auto memop = opc_0 == 1 ? MemOp::Load : MemOp::Store; + const size_t datasize = 8 << scale; + + // Operation + const u64 offset = this->ExtendReg(64, Rm, option, shift); + + u64 address; + if (Rn == Reg::SP) { + address = this->GetSp(); + } else { + address = this->GetReg(Rn); + } + address += offset; + + switch (memop) { + case MemOp::Store: { + u128 data = VectorGetElement(this->GetVec(Vt), datasize); + m_memory.WriteBlock(address, &data, datasize / 8); + break; + } + case MemOp::Load: { + u128 data{}; + m_memory.ReadBlock(address, &data, datasize / 8); + this->SetVec(Vt, data); + break; + } + default: + UNREACHABLE(); + } + + return true; +} + +bool InterpreterVisitor::STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, + Reg Rn, Vec Vt) { + const Imm<1> opc_0{0}; + const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>(); + if (scale > 4) { + // Unallocated encoding + return false; + } + const u8 shift = S ? static_cast<u8>(scale) : 0; + if (!option.Bit<1>()) { + // Unallocated encoding + return false; + } + return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt); +} + +bool InterpreterVisitor::LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, + Reg Rn, Vec Vt) { + const Imm<1> opc_0{1}; + const size_t scale = Dynarmic::concatenate(opc_1, size).ZeroExtend<size_t>(); + if (scale > 4) { + // Unallocated encoding + return false; + } + const u8 shift = S ? static_cast<u8>(scale) : 0; + if (!option.Bit<1>()) { + // Unallocated encoding + return false; + } + return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt); +} + +std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context, + fpsimd_context* fpsimd_context) { + // Construct the interpreter. + std::span<u64, 31> regs(reinterpret_cast<u64*>(context->regs), 31); + std::span<u128, 32> vregs(reinterpret_cast<u128*>(fpsimd_context->vregs), 32); + u64& sp = *reinterpret_cast<u64*>(&context->sp); + const u64& pc = *reinterpret_cast<u64*>(&context->pc); + + InterpreterVisitor visitor(memory, regs, vregs, sp, pc); + + // Read the instruction at the program counter. + u32 instruction = memory.Read32(pc); + bool was_executed = false; + + // Interpret the instruction. + if (auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction)) { + was_executed = decoder->get().call(visitor, instruction); + } else { + LOG_ERROR(Core_ARM, "Unallocated encoding: {:#x}", instruction); + } + + if (was_executed) { + return pc + 4; + } + + return std::nullopt; +} + +} // namespace Core diff --git a/src/core/arm/nce/interpreter_visitor.h b/src/core/arm/nce/interpreter_visitor.h new file mode 100644 index 000000000..f90d876ab --- /dev/null +++ b/src/core/arm/nce/interpreter_visitor.h @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2023 merryhime <https://mary.rs> +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <signal.h> +#include <unistd.h> + +#include "core/arm/nce/visitor_base.h" + +namespace Core { + +namespace Memory { +class Memory; +} + +class InterpreterVisitor final : public VisitorBase { +public: + explicit InterpreterVisitor(Core::Memory::Memory& memory, std::span<u64, 31> regs, + std::span<u128, 32> fpsimd_regs, u64& sp, const u64& pc) + : m_memory(memory), m_regs(regs), m_fpsimd_regs(fpsimd_regs), m_sp(sp), m_pc(pc) {} + ~InterpreterVisitor() override = default; + + enum class MemOp { + Load, + Store, + Prefetch, + }; + + u128 GetVec(Vec v); + u64 GetReg(Reg r); + u64 GetSp(); + u64 GetPc(); + + void SetVec(Vec v, u128 value); + void SetReg(Reg r, u64 value); + void SetSp(u64 value); + + u64 ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift); + + // Loads and stores - Load/Store Exclusive + bool Ordered(size_t size, bool L, bool o0, Reg Rn, Reg Rt); + bool STLLR(Imm<2> size, Reg Rn, Reg Rt) override; + bool STLR(Imm<2> size, Reg Rn, Reg Rt) override; + bool LDLAR(Imm<2> size, Reg Rn, Reg Rt) override; + bool LDAR(Imm<2> size, Reg Rn, Reg Rt) override; + + // Loads and stores - Load register (literal) + bool LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) override; + bool LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) override; + + // Loads and stores - Load/Store register pair + bool STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Reg Rt2, + Reg Rn, Reg Rt) override; + bool STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Vec Vt2, + Reg Rn, Vec Vt) override; + + // Loads and stores - Load/Store register (immediate) + bool RegisterImmediate(bool wback, bool postindex, size_t scale, u64 offset, Imm<2> size, + Imm<2> opc, Reg Rn, Reg Rt); + bool STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn, + Reg Rt) override; + bool STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) override; + bool STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) override; + + bool SIMDImmediate(bool wback, bool postindex, size_t scale, u64 offset, MemOp memop, Reg Rn, + Vec Vt); + bool STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn, + Vec Vt) override; + bool STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) override; + bool LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn, + Vec Vt) override; + bool LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) override; + bool STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) override; + bool LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) override; + + // Loads and stores - Load/Store register (register offset) + bool RegisterOffset(size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1, Imm<1> opc_0, Reg Rm, + Imm<3> option, Reg Rn, Reg Rt); + bool STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Reg Rt) override; + bool LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Reg Rt) override; + + bool SIMDOffset(size_t scale, u8 shift, Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Vec Vt); + bool STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Vec Vt) override; + bool LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Vec Vt) override; + +private: + Core::Memory::Memory& m_memory; + std::span<u64, 31> m_regs; + std::span<u128, 32> m_fpsimd_regs; + u64& m_sp; + const u64& m_pc; +}; + +std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context, + fpsimd_context* fpsimd_context); + +} // namespace Core diff --git a/src/core/arm/nce/visitor_base.h b/src/core/arm/nce/visitor_base.h new file mode 100644 index 000000000..8fb032912 --- /dev/null +++ b/src/core/arm/nce/visitor_base.h @@ -0,0 +1,2777 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2023 merryhime <https://mary.rs> +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <dynarmic/frontend/A64/a64_types.h> +#include <dynarmic/frontend/imm.h> + +namespace Core { + +class VisitorBase { +public: + using instruction_return_type = bool; + + template <size_t BitSize> + using Imm = Dynarmic::Imm<BitSize>; + using Reg = Dynarmic::A64::Reg; + using Vec = Dynarmic::A64::Vec; + using Cond = Dynarmic::A64::Cond; + + virtual ~VisitorBase() {} + + virtual bool UnallocatedEncoding() { + return false; + } + + // Data processing - Immediate - PC relative addressing + virtual bool ADR(Imm<2> immlo, Imm<19> immhi, Reg Rd) { + return false; + } + virtual bool ADRP(Imm<2> immlo, Imm<19> immhi, Reg Rd) { + return false; + } + + // Data processing - Immediate - Add/Sub (with tag) + virtual bool ADDG(Imm<6> offset_imm, Imm<4> tag_offset, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUBG(Imm<6> offset_imm, Imm<4> tag_offset, Reg Rn, Reg Rd) { + return false; + } + + // Data processing - Immediate - Add/Sub + virtual bool ADD_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) { + return false; + } + virtual bool ADDS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUB_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUBS_imm(bool sf, Imm<2> shift, Imm<12> imm12, Reg Rn, Reg Rd) { + return false; + } + + // Data processing - Immediate - Logical + virtual bool AND_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) { + return false; + } + virtual bool ORR_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) { + return false; + } + virtual bool EOR_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) { + return false; + } + virtual bool ANDS_imm(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) { + return false; + } + + // Data processing - Immediate - Move Wide + virtual bool MOVN(bool sf, Imm<2> hw, Imm<16> imm16, Reg Rd) { + return false; + } + virtual bool MOVZ(bool sf, Imm<2> hw, Imm<16> imm16, Reg Rd) { + return false; + } + virtual bool MOVK(bool sf, Imm<2> hw, Imm<16> imm16, Reg Rd) { + return false; + } + + // Data processing - Immediate - Bitfield + virtual bool SBFM(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) { + return false; + } + virtual bool BFM(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) { + return false; + } + virtual bool UBFM(bool sf, bool N, Imm<6> immr, Imm<6> imms, Reg Rn, Reg Rd) { + return false; + } + virtual bool ASR_1(Imm<5> immr, Reg Rn, Reg Rd) { + return false; + } + virtual bool ASR_2(Imm<6> immr, Reg Rn, Reg Rd) { + return false; + } + virtual bool SXTB_1(Reg Rn, Reg Rd) { + return false; + } + virtual bool SXTB_2(Reg Rn, Reg Rd) { + return false; + } + virtual bool SXTH_1(Reg Rn, Reg Rd) { + return false; + } + virtual bool SXTH_2(Reg Rn, Reg Rd) { + return false; + } + virtual bool SXTW(Reg Rn, Reg Rd) { + return false; + } + + // Data processing - Immediate - Extract + virtual bool EXTR(bool sf, bool N, Reg Rm, Imm<6> imms, Reg Rn, Reg Rd) { + return false; + } + + // Conditional branch + virtual bool B_cond(Imm<19> imm19, Cond cond) { + return false; + } + + // Exception generation + virtual bool SVC(Imm<16> imm16) { + return false; + } + virtual bool HVC(Imm<16> imm16) { + return false; + } + virtual bool SMC(Imm<16> imm16) { + return false; + } + virtual bool BRK(Imm<16> imm16) { + return false; + } + virtual bool HLT(Imm<16> imm16) { + return false; + } + virtual bool DCPS1(Imm<16> imm16) { + return false; + } + virtual bool DCPS2(Imm<16> imm16) { + return false; + } + virtual bool DCPS3(Imm<16> imm16) { + return false; + } + + // System + virtual bool MSR_imm(Imm<3> op1, Imm<4> CRm, Imm<3> op2) { + return false; + } + virtual bool HINT(Imm<4> CRm, Imm<3> op2) { + return false; + } + virtual bool NOP() { + return false; + } + virtual bool YIELD() { + return false; + } + virtual bool WFE() { + return false; + } + virtual bool WFI() { + return false; + } + virtual bool SEV() { + return false; + } + virtual bool SEVL() { + return false; + } + virtual bool XPAC_1(bool D, Reg Rd) { + return false; + } + virtual bool XPAC_2() { + return false; + } + virtual bool PACIA_1(bool Z, Reg Rn, Reg Rd) { + return false; + } + virtual bool PACIA_2() { + return false; + } + virtual bool PACIB_1(bool Z, Reg Rn, Reg Rd) { + return false; + } + virtual bool PACIB_2() { + return false; + } + virtual bool AUTIA_1(bool Z, Reg Rn, Reg Rd) { + return false; + } + virtual bool AUTIA_2() { + return false; + } + virtual bool AUTIB_1(bool Z, Reg Rn, Reg Rd) { + return false; + } + virtual bool AUTIB_2() { + return false; + } + virtual bool BTI(Imm<2> upper_op2) { + return false; + } + virtual bool ESB() { + return false; + } + virtual bool PSB() { + return false; + } + virtual bool TSB() { + return false; + } + virtual bool CSDB() { + return false; + } + virtual bool CLREX(Imm<4> CRm) { + return false; + } + virtual bool DSB(Imm<4> CRm) { + return false; + } + virtual bool SSBB() { + return false; + } + virtual bool PSSBB() { + return false; + } + virtual bool DMB(Imm<4> CRm) { + return false; + } + virtual bool ISB(Imm<4> CRm) { + return false; + } + virtual bool SYS(Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { + return false; + } + virtual bool SB() { + return false; + } + virtual bool MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { + return false; + } + virtual bool SYSL(Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { + return false; + } + virtual bool MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { + return false; + } + + // System - Flag manipulation instructions + virtual bool CFINV() { + return false; + } + virtual bool RMIF(Imm<6> lsb, Reg Rn, Imm<4> mask) { + return false; + } + virtual bool SETF8(Reg Rn) { + return false; + } + virtual bool SETF16(Reg Rn) { + return false; + } + + // System - Flag format instructions + virtual bool XAFlag() { + return false; + } + virtual bool AXFlag() { + return false; + } + + // SYS: Data Cache + virtual bool DC_IVAC(Reg Rt) { + return false; + } + virtual bool DC_ISW(Reg Rt) { + return false; + } + virtual bool DC_CSW(Reg Rt) { + return false; + } + virtual bool DC_CISW(Reg Rt) { + return false; + } + virtual bool DC_ZVA(Reg Rt) { + return false; + } + virtual bool DC_CVAC(Reg Rt) { + return false; + } + virtual bool DC_CVAU(Reg Rt) { + return false; + } + virtual bool DC_CVAP(Reg Rt) { + return false; + } + virtual bool DC_CIVAC(Reg Rt) { + return false; + } + + // SYS: Instruction Cache + virtual bool IC_IALLU() { + return false; + } + virtual bool IC_IALLUIS() { + return false; + } + virtual bool IC_IVAU(Reg Rt) { + return false; + } + + // Unconditional branch (Register) + virtual bool BR(Reg Rn) { + return false; + } + virtual bool BRA(bool Z, bool M, Reg Rn, Reg Rm) { + return false; + } + virtual bool BLR(Reg Rn) { + return false; + } + virtual bool BLRA(bool Z, bool M, Reg Rn, Reg Rm) { + return false; + } + virtual bool RET(Reg Rn) { + return false; + } + virtual bool RETA(bool M) { + return false; + } + virtual bool ERET() { + return false; + } + virtual bool ERETA(bool M) { + return false; + } + virtual bool DRPS() { + return false; + } + + // Unconditional branch (immediate) + virtual bool B_uncond(Imm<26> imm26) { + return false; + } + virtual bool BL(Imm<26> imm26) { + return false; + } + + // Compare and branch (immediate) + virtual bool CBZ(bool sf, Imm<19> imm19, Reg Rt) { + return false; + } + virtual bool CBNZ(bool sf, Imm<19> imm19, Reg Rt) { + return false; + } + virtual bool TBZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) { + return false; + } + virtual bool TBNZ(Imm<1> b5, Imm<5> b40, Imm<14> imm14, Reg Rt) { + return false; + } + + // Loads and stores - Advanced SIMD Load/Store multiple structures + virtual bool STx_mult_1(bool Q, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool STx_mult_2(bool Q, Reg Rm, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LDx_mult_1(bool Q, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LDx_mult_2(bool Q, Reg Rm, Imm<4> opcode, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + + // Loads and stores - Advanced SIMD Load/Store single structures + virtual bool ST1_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool ST1_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, + Vec Vt) { + return false; + } + virtual bool ST3_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool ST3_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, + Vec Vt) { + return false; + } + virtual bool ST2_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool ST2_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, + Vec Vt) { + return false; + } + virtual bool ST4_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool ST4_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, + Vec Vt) { + return false; + } + virtual bool LD1_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD1_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, + Vec Vt) { + return false; + } + virtual bool LD3_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD3_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, + Vec Vt) { + return false; + } + virtual bool LD1R_1(bool Q, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD1R_2(bool Q, Reg Rm, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD3R_1(bool Q, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD3R_2(bool Q, Reg Rm, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD2_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD2_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, + Vec Vt) { + return false; + } + virtual bool LD4_sngl_1(bool Q, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD4_sngl_2(bool Q, Reg Rm, Imm<2> upper_opcode, bool S, Imm<2> size, Reg Rn, + Vec Vt) { + return false; + } + virtual bool LD2R_1(bool Q, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD2R_2(bool Q, Reg Rm, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD4R_1(bool Q, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + virtual bool LD4R_2(bool Q, Reg Rm, Imm<2> size, Reg Rn, Vec Vt) { + return false; + } + + // Loads and stores - Load/Store Exclusive + virtual bool STXR(Imm<2> size, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool STLXR(Imm<2> size, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool STXP(Imm<1> size, Reg Rs, Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + virtual bool STLXP(Imm<1> size, Reg Rs, Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDXR(Imm<2> size, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDAXR(Imm<2> size, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDXP(Imm<1> size, Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDAXP(Imm<1> size, Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + virtual bool STLLR(Imm<2> size, Reg Rn, Reg Rt) { + return false; + } + virtual bool STLR(Imm<2> size, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDLAR(Imm<2> size, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDAR(Imm<2> size, Reg Rn, Reg Rt) { + return false; + } + virtual bool CASP(bool sz, bool L, Reg Rs, bool o0, Reg Rn, Reg Rt) { + return false; + } + virtual bool CASB(bool L, Reg Rs, bool o0, Reg Rn, Reg Rt) { + return false; + } + virtual bool CASH(bool L, Reg Rs, bool o0, Reg Rn, Reg Rt) { + return false; + } + virtual bool CAS(bool sz, bool L, Reg Rs, bool o0, Reg Rn, Reg Rt) { + return false; + } + + // Loads and stores - Load register (literal) + virtual bool LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) { + return false; + } + virtual bool LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) { + return false; + } + virtual bool LDRSW_lit(Imm<19> imm19, Reg Rt) { + return false; + } + virtual bool PRFM_lit(Imm<19> imm19, Imm<5> prfop) { + return false; + } + + // Loads and stores - Load/Store no-allocate pair + virtual bool STNP_LDNP_gen(Imm<1> upper_opc, Imm<1> L, Imm<7> imm7, Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + virtual bool STNP_LDNP_fpsimd(Imm<2> opc, Imm<1> L, Imm<7> imm7, Vec Vt2, Reg Rn, Vec Vt) { + return false; + } + + // Loads and stores - Load/Store register pair + virtual bool STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, + Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + virtual bool STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, + Vec Vt2, Reg Rn, Vec Vt) { + return false; + } + virtual bool STGP_1(Imm<7> offset_imm, Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + virtual bool STGP_2(Imm<7> offset_imm, Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + virtual bool STGP_3(Imm<7> offset_imm, Reg Rt2, Reg Rn, Reg Rt) { + return false; + } + + // Loads and stores - Load/Store register (immediate) + virtual bool STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn, + Reg Rt) { + return false; + } + virtual bool STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) { + return false; + } + virtual bool STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool PRFM_imm(Imm<12> imm12, Reg Rn, Reg Rt) { + return false; + } + virtual bool PRFM_unscaled_imm(Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, + Reg Rn, Vec Vt) { + return false; + } + virtual bool STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) { + return false; + } + virtual bool LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, + Reg Rn, Vec Vt) { + return false; + } + virtual bool LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) { + return false; + } + virtual bool STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) { + return false; + } + virtual bool LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) { + return false; + } + + // Loads and stores - Load/Store register (unprivileged) + virtual bool STTRB(Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDTRB(Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDTRSB(Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool STTRH(Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDTRH(Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDTRSH(Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool STTR(Imm<2> size, Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDTR(Imm<2> size, Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDTRSW(Imm<9> imm9, Reg Rn, Reg Rt) { + return false; + } + + // Loads and stores - Atomic memory options + virtual bool LDADDB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDCLRB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDEORB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSETB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSMAXB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSMINB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDUMAXB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDUMINB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool SWPB(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDAPRB(Reg Rn, Reg Rt) { + return false; + } + virtual bool LDADDH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDCLRH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDEORH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSETH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSMAXH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSMINH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDUMAXH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDUMINH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool SWPH(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDAPRH(Reg Rn, Reg Rt) { + return false; + } + virtual bool LDADD(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDCLR(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDEOR(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSET(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSMAX(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDSMIN(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDUMAX(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDUMIN(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool SWP(bool A, bool R, Reg Rs, Reg Rn, Reg Rt) { + return false; + } + virtual bool LDAPR(Reg Rn, Reg Rt) { + return false; + } + + // Loads and stores - Load/Store register (register offset) + virtual bool STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Reg Rt) { + return false; + } + virtual bool LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Reg Rt) { + return false; + } + virtual bool STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Vec Vt) { + return false; + } + virtual bool LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn, + Vec Vt) { + return false; + } + + // Loads and stores - Load/Store memory tags + virtual bool STG_1(Imm<9> imm9, Reg Rn) { + return false; + } + virtual bool STG_2(Imm<9> imm9, Reg Rn) { + return false; + } + virtual bool STG_3(Imm<9> imm9, Reg Rn) { + return false; + } + virtual bool LDG(Imm<9> offset_imm, Reg Rn, Reg Rt) { + return false; + } + virtual bool STZG_1(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool STZG_2(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool STZG_3(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool ST2G_1(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool ST2G_2(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool ST2G_3(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool STGV(Reg Rn, Reg Rt) { + return false; + } + virtual bool STZ2G_1(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool STZ2G_2(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool STZ2G_3(Imm<9> offset_imm, Reg Rn) { + return false; + } + virtual bool LDGV(Reg Rn, Reg Rt) { + return false; + } + + // Loads and stores - Load/Store register (pointer authentication) + virtual bool LDRA(bool M, bool S, Imm<9> imm9, bool W, Reg Rn, Reg Rt) { + return false; + } + + // Data Processing - Register - 2 source + virtual bool UDIV(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool SDIV(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool LSLV(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool LSRV(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool ASRV(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool RORV(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool CRC32(bool sf, Reg Rm, Imm<2> sz, Reg Rn, Reg Rd) { + return false; + } + virtual bool CRC32C(bool sf, Reg Rm, Imm<2> sz, Reg Rn, Reg Rd) { + return false; + } + virtual bool PACGA(Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUBP(Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool IRG(Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool GMI(Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUBPS(Reg Rm, Reg Rn, Reg Rd) { + return false; + } + + // Data Processing - Register - 1 source + virtual bool RBIT_int(bool sf, Reg Rn, Reg Rd) { + return false; + } + virtual bool REV16_int(bool sf, Reg Rn, Reg Rd) { + return false; + } + virtual bool REV(bool sf, bool opc_0, Reg Rn, Reg Rd) { + return false; + } + virtual bool CLZ_int(bool sf, Reg Rn, Reg Rd) { + return false; + } + virtual bool CLS_int(bool sf, Reg Rn, Reg Rd) { + return false; + } + virtual bool REV32_int(Reg Rn, Reg Rd) { + return false; + } + virtual bool PACDA(bool Z, Reg Rn, Reg Rd) { + return false; + } + virtual bool PACDB(bool Z, Reg Rn, Reg Rd) { + return false; + } + virtual bool AUTDA(bool Z, Reg Rn, Reg Rd) { + return false; + } + virtual bool AUTDB(bool Z, Reg Rn, Reg Rd) { + return false; + } + + // Data Processing - Register - Logical (shifted register) + virtual bool AND_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool BIC_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool ORR_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool ORN_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool EOR_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool EON(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool ANDS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool BICS(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + + // Data Processing - Register - Add/Sub (shifted register) + virtual bool ADD_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool ADDS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUB_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUBS_shift(bool sf, Imm<2> shift, Reg Rm, Imm<6> imm6, Reg Rn, Reg Rd) { + return false; + } + + // Data Processing - Register - Add/Sub (shifted register) + virtual bool ADD_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) { + return false; + } + virtual bool ADDS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUB_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) { + return false; + } + virtual bool SUBS_ext(bool sf, Reg Rm, Imm<3> option, Imm<3> imm3, Reg Rn, Reg Rd) { + return false; + } + + // Data Processing - Register - Add/Sub (with carry) + virtual bool ADC(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool ADCS(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool SBC(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool SBCS(bool sf, Reg Rm, Reg Rn, Reg Rd) { + return false; + } + + // Data Processing - Register - Conditional compare + virtual bool CCMN_reg(bool sf, Reg Rm, Cond cond, Reg Rn, Imm<4> nzcv) { + return false; + } + virtual bool CCMP_reg(bool sf, Reg Rm, Cond cond, Reg Rn, Imm<4> nzcv) { + return false; + } + virtual bool CCMN_imm(bool sf, Imm<5> imm5, Cond cond, Reg Rn, Imm<4> nzcv) { + return false; + } + virtual bool CCMP_imm(bool sf, Imm<5> imm5, Cond cond, Reg Rn, Imm<4> nzcv) { + return false; + } + + // Data Processing - Register - Conditional select + virtual bool CSEL(bool sf, Reg Rm, Cond cond, Reg Rn, Reg Rd) { + return false; + } + virtual bool CSINC(bool sf, Reg Rm, Cond cond, Reg Rn, Reg Rd) { + return false; + } + virtual bool CSINV(bool sf, Reg Rm, Cond cond, Reg Rn, Reg Rd) { + return false; + } + virtual bool CSNEG(bool sf, Reg Rm, Cond cond, Reg Rn, Reg Rd) { + return false; + } + + // Data Processing - Register - 3 source + virtual bool MADD(bool sf, Reg Rm, Reg Ra, Reg Rn, Reg Rd) { + return false; + } + virtual bool MSUB(bool sf, Reg Rm, Reg Ra, Reg Rn, Reg Rd) { + return false; + } + virtual bool SMADDL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) { + return false; + } + virtual bool SMSUBL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) { + return false; + } + virtual bool SMULH(Reg Rm, Reg Rn, Reg Rd) { + return false; + } + virtual bool UMADDL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) { + return false; + } + virtual bool UMSUBL(Reg Rm, Reg Ra, Reg Rn, Reg Rd) { + return false; + } + virtual bool UMULH(Reg Rm, Reg Rn, Reg Rd) { + return false; + } + + // Data Processing - FP and SIMD - AES + virtual bool AESE(Vec Vn, Vec Vd) { + return false; + } + virtual bool AESD(Vec Vn, Vec Vd) { + return false; + } + virtual bool AESMC(Vec Vn, Vec Vd) { + return false; + } + virtual bool AESIMC(Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SHA + virtual bool SHA1C(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA1P(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA1M(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA1SU0(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA256H(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA256H2(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA256SU1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA1H(Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA1SU1(Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA256SU0(Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Scalar copy + virtual bool DUP_elt_1(Imm<5> imm5, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Scalar three + virtual bool FMULX_vec_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMULX_vec_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMEQ_reg_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMEQ_reg_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPS_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPS_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRSQRTS_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRSQRTS_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGE_reg_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGE_reg_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FACGE_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FACGE_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FABD_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FABD_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGT_reg_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGT_reg_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FACGT_1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FACGT_2(bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Two register misc FP16 + virtual bool FCVTNS_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTMS_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTAS_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool SCVTF_int_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGT_zero_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMEQ_zero_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLT_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTPS_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZS_int_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPE_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPX_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTNU_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTMU_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTAU_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool UCVTF_int_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGE_zero_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLE_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTPU_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZU_int_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FRSQRTE_1(Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Two register misc + virtual bool FCVTNS_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTMS_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTAS_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool SCVTF_int_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGT_zero_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMEQ_zero_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLT_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTPS_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZS_int_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPE_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPX_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTNU_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTMU_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTAU_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool UCVTF_int_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGE_zero_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLE_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTPU_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZU_int_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRSQRTE_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Scalar two register misc FP16 + virtual bool FCVTNS_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTMS_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTAS_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool SCVTF_int_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGT_zero_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMEQ_zero_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLT_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTPS_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZS_int_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPE_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTNU_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTMU_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTAU_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool UCVTF_int_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGE_zero_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLE_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTPU_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZU_int_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRSQRTE_3(bool Q, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Scalar two register misc + virtual bool FCVTNS_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTMS_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTAS_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool SCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGT_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMEQ_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLT_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTPS_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZS_int_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPE_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTNU_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTMU_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTAU_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool UCVTF_int_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGE_zero_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLE_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTPU_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZU_int_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRSQRTE_4(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Scalar three same extra + virtual bool SQRDMLAH_vec_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRDMLAH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRDMLSH_vec_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRDMLSH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Scalar two-register misc + virtual bool SUQADD_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQABS_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMGT_zero_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMEQ_zero_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMLT_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool ABS_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQXTN_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool USQADD_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQNEG_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMGE_zero_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMLE_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool NEG_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQXTUN_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQXTN_1(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTXN_1(bool sz, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Scalar pairwise + virtual bool ADDP_pair(Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNMP_pair_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNMP_pair_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FADDP_pair_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FADDP_pair_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXP_pair_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXP_pair_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNMP_pair_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNMP_pair_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINP_pair_1(Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINP_pair_2(bool sz, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Scalar three different + virtual bool SQDMLAL_vec_1(Imm<2> size, Reg Rm, Reg Rn, Vec Vd) { + return false; + } + virtual bool SQDMLSL_vec_1(Imm<2> size, Reg Rm, Reg Rn, Vec Vd) { + return false; + } + virtual bool SQDMULL_vec_1(Imm<2> size, Reg Rm, Reg Rn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Scalar three same + virtual bool SQADD_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSUB_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMGT_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMGE_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool ADD_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMTST_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQDMULH_vec_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQADD_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQSUB_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMHI_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMHS_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool USHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQSHL_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool URSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQRSHL_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SUB_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMEQ_reg_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRDMULH_vec_1(Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Scalar shift by immediate + virtual bool SSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHL_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHL_imm_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZS_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool USHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool USRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool URSHR_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool URSRA_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRI_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SLI_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHLU_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQSHL_imm_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHRUN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRSHRUN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQRSHRN_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool UCVTF_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZU_fix_1(Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Scalar x indexed element + virtual bool SQDMLAL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQDMLSL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQDMULL_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQRDMULH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMLA_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLA_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLS_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLS_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMUL_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMUL_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRDMLAH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQRDMLSH_elt_1(Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMULX_elt_1(Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMULX_elt_2(bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Table Lookup + virtual bool TBL(bool Q, Vec Vm, Imm<2> len, size_t Vn, Vec Vd) { + return false; + } + virtual bool TBX(bool Q, Vec Vm, Imm<2> len, size_t Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Permute + virtual bool UZP1(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool TRN1(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool ZIP1(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UZP2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool TRN2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool ZIP2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Extract + virtual bool EXT(bool Q, Vec Vm, Imm<4> imm4, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Copy + virtual bool DUP_elt_2(bool Q, Imm<5> imm5, Vec Vn, Vec Vd) { + return false; + } + virtual bool DUP_gen(bool Q, Imm<5> imm5, Reg Rn, Vec Vd) { + return false; + } + virtual bool SMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) { + return false; + } + virtual bool UMOV(bool Q, Imm<5> imm5, Vec Vn, Reg Rd) { + return false; + } + virtual bool INS_gen(Imm<5> imm5, Reg Rn, Vec Vd) { + return false; + } + virtual bool INS_elt(Imm<5> imm5, Imm<4> imm4, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Three same + virtual bool FMULX_vec_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMEQ_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPS_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRSQRTS_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGE_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FACGE_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FABD_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGT_reg_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FACGT_3(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNM_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLA_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FADD_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAX_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNM_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLS_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FSUB_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMIN_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNMP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FADDP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMUL_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FDIV_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNMP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINP_vec_1(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Three same extra + virtual bool SDOT_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UDOT_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMLA_vec(bool Q, Imm<2> size, Vec Vm, Imm<2> rot, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCADD_vec(bool Q, Imm<2> size, Vec Vm, Imm<1> rot, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Two register misc + virtual bool REV64_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool REV16_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CLS_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CNT(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool XTN(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTN(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTL(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool URECPE(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool REV32_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool UADDLP(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CLZ_asimd(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool UADALP(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHLL(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool NOT(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool RBIT_asimd(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool URSQRTE(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool SUQADD_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQABS_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMGT_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMEQ_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMLT_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool ABS_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQXTN_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool USQADD_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQNEG_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMGE_zero_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMLE_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool NEG_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQXTUN_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQXTN_2(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTXN_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTN_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTN_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTM_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTM_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FABS_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FABS_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTP_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTP_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTZ_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTZ_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTA_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTA_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTX_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTX_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FNEG_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FNEG_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTI_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTI_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FSQRT_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FSQRT_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINT32X_1(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINT64X_1(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINT32Z_1(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINT64Z_1(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD across lanes + virtual bool SADDLV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMAXV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMINV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool ADDV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNMV_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNMV_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXV_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXV_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNMV_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNMV_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINV_1(bool Q, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINV_2(bool Q, bool sz, Vec Vn, Vec Vd) { + return false; + } + virtual bool UADDLV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMAXV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMINV(bool Q, Imm<2> size, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD three different + virtual bool SADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SSUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SSUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool ADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool PMULL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UADDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UADDW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool USUBL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool USUBW(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool RADDHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UABAL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool RSUBHN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UABDL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMLAL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMLSL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMULL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQDMLAL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQDMLSL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQDMULL_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD three same + virtual bool SHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool MLA_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool MUL_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool ADDP_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLAL_vec_1(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLAL_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool AND_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool BIC_asimd_reg(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLSL_vec_1(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLSL_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool ORR_asimd_reg(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool ORN_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool URHADD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UHSUB(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMAX(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMIN(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UABD(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UABA(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool MLS_vec(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool PMUL(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMAXP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UMINP(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool EOR_asimd(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool BSL(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool BIT(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool BIF(bool Q, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLA_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FADD_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAX_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNM_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLS_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FSUB_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMIN_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FADDP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMUL_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FDIV_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNMP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINP_vec_2(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMULX_vec_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMEQ_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRECPS_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRSQRTS_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGE_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FACGE_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FABD_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCMGT_reg_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FACGT_4(bool Q, bool sz, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMGT_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMGE_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool ADD_vector(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMTST_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQADD_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQSUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMHI_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMHS_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool USHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQSHL_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool URSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQRSHL_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SUB_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool CMEQ_reg_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRDMULH_vec_2(bool Q, Imm<2> size, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD modified immediate + virtual bool MOVI(bool Q, bool op, Imm<1> a, Imm<1> b, Imm<1> c, Imm<4> cmode, Imm<1> d, + Imm<1> e, Imm<1> f, Imm<1> g, Imm<1> h, Vec Vd) { + return false; + } + virtual bool FMOV_2(bool Q, bool op, Imm<1> a, Imm<1> b, Imm<1> c, Imm<1> d, Imm<1> e, Imm<1> f, + Imm<1> g, Imm<1> h, Vec Vd) { + return false; + } + virtual bool FMOV_3(bool Q, Imm<1> a, Imm<1> b, Imm<1> c, Imm<1> d, Imm<1> e, Imm<1> f, + Imm<1> g, Imm<1> h, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD Shift by immediate + virtual bool SSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHL_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool RSHRN(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SSHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZS_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool USHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool USRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool URSHR_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool URSRA_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SRI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SLI_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHLU_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQSHL_imm_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRSHRUN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool UQRSHRN_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool USHLL(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool UCVTF_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVTZU_fix_2(bool Q, Imm<4> immh, Imm<3> immb, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SIMD vector x indexed element + virtual bool SMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQDMLAL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, + Vec Vn, Vec Vd) { + return false; + } + virtual bool SMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQDMLSL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, + Vec Vn, Vec Vd) { + return false; + } + virtual bool MUL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vm, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQDMULL_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, + Vec Vn, Vec Vd) { + return false; + } + virtual bool SQDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, + Vec Vn, Vec Vd) { + return false; + } + virtual bool SQRDMULH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, + Vec Vn, Vec Vd) { + return false; + } + virtual bool SDOT_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMLA_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLA_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMLS_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMLS_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMUL_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMUL_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMLAL_elt_1(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMLAL_elt_2(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMLSL_elt_1(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FMLSL_elt_2(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool MLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool UMLAL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool MLS_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool UMLSL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool UMULL_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQRDMLAH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, + Vec Vn, Vec Vd) { + return false; + } + virtual bool UDOT_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool SQRDMLSH_elt_2(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, + Vec Vn, Vec Vd) { + return false; + } + virtual bool FMULX_elt_3(bool Q, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMULX_elt_4(bool Q, bool sz, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<1> H, Vec Vn, + Vec Vd) { + return false; + } + virtual bool FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4> Vmlo, Imm<2> rot, + Imm<1> H, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Cryptographic three register + virtual bool SM3TT1A(Vec Vm, Imm<2> imm2, Vec Vn, Vec Vd) { + return false; + } + virtual bool SM3TT1B(Vec Vm, Imm<2> imm2, Vec Vn, Vec Vd) { + return false; + } + virtual bool SM3TT2A(Vec Vm, Imm<2> imm2, Vec Vn, Vec Vd) { + return false; + } + virtual bool SM3TT2B(Vec Vm, Imm<2> imm2, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SHA512 three register + virtual bool SHA512H(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA512H2(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SHA512SU1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool RAX1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool XAR(Vec Vm, Imm<6> imm6, Vec Vn, Vec Vd) { + return false; + } + virtual bool SM3PARTW1(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SM3PARTW2(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool SM4EKEY(Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Cryptographic four register + virtual bool EOR3(Vec Vm, Vec Va, Vec Vn, Vec Vd) { + return false; + } + virtual bool BCAX(Vec Vm, Vec Va, Vec Vn, Vec Vd) { + return false; + } + virtual bool SM3SS1(Vec Vm, Vec Va, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - SHA512 two register + virtual bool SHA512SU0(Vec Vn, Vec Vd) { + return false; + } + virtual bool SM4E(Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Conversion between floating point and fixed point + virtual bool SCVTF_float_fix(bool sf, Imm<2> type, Imm<6> scale, Reg Rn, Vec Vd) { + return false; + } + virtual bool UCVTF_float_fix(bool sf, Imm<2> type, Imm<6> scale, Reg Rn, Vec Vd) { + return false; + } + virtual bool FCVTZS_float_fix(bool sf, Imm<2> type, Imm<6> scale, Vec Vn, Reg Rd) { + return false; + } + virtual bool FCVTZU_float_fix(bool sf, Imm<2> type, Imm<6> scale, Vec Vn, Reg Rd) { + return false; + } + + // Data Processing - FP and SIMD - Conversion between floating point and integer + virtual bool FCVTNS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FCVTNU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool SCVTF_float_int(bool sf, Imm<2> type, Reg Rn, Vec Vd) { + return false; + } + virtual bool UCVTF_float_int(bool sf, Imm<2> type, Reg Rn, Vec Vd) { + return false; + } + virtual bool FCVTAS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FCVTAU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FMOV_float_gen(bool sf, Imm<2> type, Imm<1> rmode_0, Imm<1> opc_0, size_t n, + size_t d) { + return false; + } + virtual bool FCVTPS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FCVTPU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FCVTMS_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FCVTMU_float(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FCVTZS_float_int(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FCVTZU_float_int(bool sf, Imm<2> type, Vec Vn, Reg Rd) { + return false; + } + virtual bool FJCVTZS(Vec Vn, Reg Rd) { + return false; + } + + // Data Processing - FP and SIMD - Floating point data processing + virtual bool FMOV_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FABS_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FNEG_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FSQRT_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FCVT_float(Imm<2> type, Imm<2> opc, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTN_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTP_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTM_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTZ_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTA_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTX_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINTI_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINT32X_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINT64X_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINT32Z_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + virtual bool FRINT64Z_float(Imm<2> type, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Floating point compare + virtual bool FCMP_float(Imm<2> type, Vec Vm, Vec Vn, bool cmp_with_zero) { + return false; + } + virtual bool FCMPE_float(Imm<2> type, Vec Vm, Vec Vn, bool cmp_with_zero) { + return false; + } + + // Data Processing - FP and SIMD - Floating point immediate + virtual bool FMOV_float_imm(Imm<2> type, Imm<8> imm8, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Floating point conditional compare + virtual bool FCCMP_float(Imm<2> type, Vec Vm, Cond cond, Vec Vn, Imm<4> nzcv) { + return false; + } + virtual bool FCCMPE_float(Imm<2> type, Vec Vm, Cond cond, Vec Vn, Imm<4> nzcv) { + return false; + } + + // Data Processing - FP and SIMD - Floating point data processing two register + virtual bool FMUL_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FDIV_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FADD_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FSUB_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAX_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMIN_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMAXNM_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMINNM_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + virtual bool FNMUL_float(Imm<2> type, Vec Vm, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Floating point conditional select + virtual bool FCSEL_float(Imm<2> type, Vec Vm, Cond cond, Vec Vn, Vec Vd) { + return false; + } + + // Data Processing - FP and SIMD - Floating point data processing three register + virtual bool FMADD_float(Imm<2> type, Vec Vm, Vec Va, Vec Vn, Vec Vd) { + return false; + } + virtual bool FMSUB_float(Imm<2> type, Vec Vm, Vec Va, Vec Vn, Vec Vd) { + return false; + } + virtual bool FNMADD_float(Imm<2> type, Vec Vm, Vec Va, Vec Vn, Vec Vd) { + return false; + } + virtual bool FNMSUB_float(Imm<2> type, Vec Vm, Vec Va, Vec Vn, Vec Vd) { + return false; + } +}; + +} // namespace Core diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 639842401..b7105c8ff 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -201,8 +201,6 @@ std::string VfsFile::GetFullPath() const { VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const { auto vec = Common::FS::SplitPathComponents(path); - vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), - vec.end()); if (vec.empty()) { return nullptr; } @@ -237,8 +235,6 @@ VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const { VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const { auto vec = Common::FS::SplitPathComponents(path); - vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), - vec.end()); if (vec.empty()) { // TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently // because of const-ness @@ -303,8 +299,6 @@ std::size_t VfsDirectory::GetSize() const { VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) { auto vec = Common::FS::SplitPathComponents(path); - vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), - vec.end()); if (vec.empty()) { return nullptr; } @@ -334,8 +328,6 @@ VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) { VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) { auto vec = Common::FS::SplitPathComponents(path); - vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), - vec.end()); if (vec.empty()) { return nullptr; } diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 1c706e4d8..cd9b79786 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -268,7 +268,7 @@ void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_, const std::string& path_, Mode perms_, std::optional<u64> size_) : base(base_), reference(std::move(reference_)), path(path_), - parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponents(path_)), + parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponentsCopy(path_)), size(size_), perms(perms_) {} RealVfsFile::~RealVfsFile() { @@ -276,7 +276,7 @@ RealVfsFile::~RealVfsFile() { } std::string RealVfsFile::GetName() const { - return path_components.back(); + return path_components.empty() ? "" : std::string(path_components.back()); } std::size_t RealVfsFile::GetSize() const { @@ -375,7 +375,7 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_) : base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)), - path_components(FS::SplitPathComponents(path)), perms(perms_) { + path_components(FS::SplitPathComponentsCopy(path)), perms(perms_) { if (!FS::Exists(path) && True(perms & Mode::Write)) { void(FS::CreateDirs(path)); } @@ -464,7 +464,7 @@ bool RealVfsDirectory::IsReadable() const { } std::string RealVfsDirectory::GetName() const { - return path_components.back(); + return path_components.empty() ? "" : std::string(path_components.back()); } VirtualDir RealVfsDirectory::GetParentDirectory() const { 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_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 4c416d809..423289145 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp @@ -81,6 +81,11 @@ void InvalidateInstructionCache(KernelCore& kernel, AddressType addr, u64 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> Result InvalidateDataCache(AddressType addr, u64 size) { R_SUCCEED(); @@ -1363,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. @@ -1570,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. @@ -2159,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. diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 8cb05ca0b..e479dacde 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -135,7 +135,6 @@ struct KernelCore::Impl { obj = nullptr; } }; - CleanupObject(hid_shared_mem); CleanupObject(font_shared_mem); CleanupObject(irs_shared_mem); CleanupObject(time_shared_mem); @@ -744,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); @@ -1190,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; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 69b5bbd6c..78c88902c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -239,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/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 508db7360..780f8c74d 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -104,11 +104,7 @@ Result VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) con const auto components = Common::FS::SplitPathComponents(path); std::string relative_path; for (const auto& component : components) { - // Skip empty path components - if (component.empty()) { - continue; - } - relative_path = Common::FS::SanitizePath(relative_path + '/' + component); + relative_path = Common::FS::SanitizePath(fmt::format("{}/{}", relative_path, component)); auto new_dir = backing->CreateSubdirectory(relative_path); if (new_dir == nullptr) { // TODO(DarkLordZach): Find a better error code for this diff --git a/src/core/hle/service/hid/controllers/applet_resource.cpp b/src/core/hle/service/hid/controllers/applet_resource.cpp index 435b86233..c8e74c764 100644 --- a/src/core/hle/service/hid/controllers/applet_resource.cpp +++ b/src/core/hle/service/hid/controllers/applet_resource.cpp @@ -4,6 +4,7 @@ #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 { @@ -23,11 +24,24 @@ Result AppletResource::CreateAppletResource(u64 aruid) { return ResultAruidAlreadyRegistered; } - // TODO: Here shared memory is created for the process we don't quite emulate this part so - // obtain this pointer from system - auto& shared_memory = system.Kernel().GetHidSharedMem(); + 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_handle = &shared_memory; + data[index].shared_memory_format = shared_memory_format; data[index].flag.is_assigned.Assign(true); // TODO: InitializeSixAxisControllerConfig(false); active_aruid = aruid; @@ -94,7 +108,7 @@ void AppletResource::UnregisterAppletResourceUserId(u64 aruid) { if (index < AruidIndexMax) { if (data[index].flag.is_assigned) { - data[index].shared_memory_handle = nullptr; + data[index].shared_memory_format = nullptr; data[index].flag.is_assigned.Assign(false); } } @@ -120,7 +134,7 @@ void AppletResource::FreeAppletResourceId(u64 aruid) { auto& aruid_data = data[index]; if (aruid_data.flag.is_assigned) { - aruid_data.shared_memory_handle = nullptr; + aruid_data.shared_memory_format = nullptr; aruid_data.flag.is_assigned.Assign(false); } } @@ -135,7 +149,18 @@ Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, return ResultAruidNotRegistered; } - *out_handle = data[index].shared_memory_handle; + *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; } diff --git a/src/core/hle/service/hid/controllers/applet_resource.h b/src/core/hle/service/hid/controllers/applet_resource.h index 62137db13..e7991f93a 100644 --- a/src/core/hle/service/hid/controllers/applet_resource.h +++ b/src/core/hle/service/hid/controllers/applet_resource.h @@ -8,6 +8,7 @@ #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; @@ -18,6 +19,8 @@ class KSharedMemory; } namespace Service::HID { +struct SharedMemoryFormat; + class AppletResource { public: explicit AppletResource(Core::System& system_); @@ -32,6 +35,7 @@ public: u64 GetActiveAruid(); Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid); + Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid); u64 GetIndexFromAruid(u64 aruid); @@ -80,12 +84,13 @@ private: struct AruidData { DataStatusFlag flag{}; u64 aruid{}; - Kernel::KSharedMemory* shared_memory_handle{nullptr}; + 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; 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/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp index b06ea467e..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 { @@ -1099,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; }; @@ -1122,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); @@ -1157,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); @@ -1173,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."); @@ -1182,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, @@ -1205,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 @@ -1257,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); @@ -1349,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."); @@ -1359,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, @@ -2315,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 4d33456a3..5cc88c4a1 100644 --- a/src/core/hle/service/hid/hid_system_server.cpp +++ b/src/core/hle/service/hid/hid_system_server.cpp @@ -5,6 +5,7 @@ #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" @@ -328,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}; diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp index 89cdc19cc..6c6cbd802 100644 --- a/src/core/hle/service/hid/resource_manager.cpp +++ b/src/core/hle/service/hid/resource_manager.cpp @@ -18,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 { @@ -45,40 +45,43 @@ 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 { @@ -101,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; } @@ -163,7 +170,11 @@ Result ResourceManager::CreateAppletResource(u64 aruid) { Result ResourceManager::CreateAppletResourceImpl(u64 aruid) { std::scoped_lock lock{shared_mutex}; - return applet_resource->CreateAppletResource(aruid); + const auto result = applet_resource->CreateAppletResource(aruid); + if (result.IsSuccess()) { + InitializeController(aruid); + } + return result; } Result ResourceManager::RegisterCoreAppletResource() { @@ -220,6 +231,7 @@ 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); @@ -227,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) { diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h index 15c1beb1a..5ad7cb564 100644 --- a/src/core/hle/service/hid/resource_manager.h +++ b/src/core/hle/service/hid/resource_manager.h @@ -31,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; @@ -46,12 +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; @@ -96,6 +98,7 @@ private: 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; @@ -107,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; 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 75bf31e32..2fef6cc1a 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -204,8 +204,9 @@ Result FbShareBufferManager::Initialize(u64* out_buffer_id, u64* out_layer_id, u // Record the display id. m_display_id = display_id; - // Create a layer for the display. + // Create and open a layer for the display. m_layer_id = m_flinger.CreateLayer(m_display_id).value(); + m_flinger.OpenLayer(m_layer_id); // Set up the buffer. m_buffer_id = m_next_buffer_id++; diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index 0745434c5..6352b09a9 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -176,17 +176,37 @@ void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) { display.CreateLayer(layer_id, buffer_id, nvdrv->container); } +void Nvnflinger::OpenLayer(u64 layer_id) { + const auto lock_guard = Lock(); + + for (auto& display : displays) { + if (auto* layer = display.FindLayer(layer_id); layer) { + layer->Open(); + } + } +} + void Nvnflinger::CloseLayer(u64 layer_id) { const auto lock_guard = Lock(); for (auto& display : displays) { - display.CloseLayer(layer_id); + if (auto* layer = display.FindLayer(layer_id); layer) { + layer->Close(); + } + } +} + +void Nvnflinger::DestroyLayer(u64 layer_id) { + const auto lock_guard = Lock(); + + for (auto& display : displays) { + display.DestroyLayer(layer_id); } } std::optional<u32> Nvnflinger::FindBufferQueueId(u64 display_id, u64 layer_id) { const auto lock_guard = Lock(); - const auto* const layer = FindOrCreateLayer(display_id, layer_id); + const auto* const layer = FindLayer(display_id, layer_id); if (layer == nullptr) { return std::nullopt; @@ -240,24 +260,6 @@ VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) { return display->FindLayer(layer_id); } -VI::Layer* Nvnflinger::FindOrCreateLayer(u64 display_id, u64 layer_id) { - auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return nullptr; - } - - auto* layer = display->FindLayer(layer_id); - - if (layer == nullptr) { - LOG_DEBUG(Service_Nvnflinger, "Layer at id {} not found. Trying to create it.", layer_id); - CreateLayerAtId(*display, layer_id); - return display->FindLayer(layer_id); - } - - return layer; -} - void Nvnflinger::Compose() { for (auto& display : displays) { // Trigger vsync for this display at the end of drawing diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index f5d73acdb..871285764 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -73,9 +73,15 @@ public: /// If an invalid display ID is specified, then an empty optional is returned. [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id); + /// Opens a layer on all displays for the given layer ID. + void OpenLayer(u64 layer_id); + /// Closes a layer on all displays for the given layer ID. void CloseLayer(u64 layer_id); + /// Destroys the given layer ID. + void DestroyLayer(u64 layer_id); + /// Finds the buffer queue ID of the specified layer in the specified display. /// /// If an invalid display ID or layer ID is provided, then an empty optional is returned. @@ -117,11 +123,6 @@ private: /// Finds the layer identified by the specified ID in the desired display. [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id); - /// Finds the layer identified by the specified ID in the desired display, - /// or creates the layer if it is not found. - /// To be used when the system expects the specified ID to already exist. - [[nodiscard]] VI::Layer* FindOrCreateLayer(u64 display_id, u64 layer_id); - /// Creates a layer with the specified layer ID in the desired display. void CreateLayerAtId(VI::Display& display, u64 layer_id); diff --git a/src/core/hle/service/set/appln_settings.cpp b/src/core/hle/service/set/appln_settings.cpp new file mode 100644 index 000000000..a5d802757 --- /dev/null +++ b/src/core/hle/service/set/appln_settings.cpp @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/appln_settings.h" + +namespace Service::Set { + +ApplnSettings DefaultApplnSettings() { + return {}; +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/appln_settings.h b/src/core/hle/service/set/appln_settings.h new file mode 100644 index 000000000..b07df0ee7 --- /dev/null +++ b/src/core/hle/service/set/appln_settings.h @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "common/common_types.h" + +namespace Service::Set { +struct ApplnSettings { + std::array<u8, 0x10> reserved_000; + + // nn::util::Uuid MiiAuthorId, copied from system settings 0x94B0 + std::array<u8, 0x10> mii_author_id; + + std::array<u8, 0x30> reserved_020; + + // nn::settings::system::ServiceDiscoveryControlSettings + std::array<u8, 0x4> service_discovery_control_settings; + + std::array<u8, 0x20> reserved_054; + + bool in_repair_process_enable_flag; + + std::array<u8, 0x3> pad_075; +}; +static_assert(offsetof(ApplnSettings, mii_author_id) == 0x10); +static_assert(offsetof(ApplnSettings, service_discovery_control_settings) == 0x50); +static_assert(offsetof(ApplnSettings, in_repair_process_enable_flag) == 0x74); +static_assert(sizeof(ApplnSettings) == 0x78, "ApplnSettings has the wrong size!"); + +ApplnSettings DefaultApplnSettings(); + +} // namespace Service::Set diff --git a/src/core/hle/service/set/device_settings.cpp b/src/core/hle/service/set/device_settings.cpp new file mode 100644 index 000000000..e423ce38a --- /dev/null +++ b/src/core/hle/service/set/device_settings.cpp @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/device_settings.h" + +namespace Service::Set { + +DeviceSettings DefaultDeviceSettings() { + return {}; +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/device_settings.h b/src/core/hle/service/set/device_settings.h new file mode 100644 index 000000000..b6cfe04f2 --- /dev/null +++ b/src/core/hle/service/set/device_settings.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "common/common_types.h" + +namespace Service::Set { +struct DeviceSettings { + std::array<u8, 0x10> reserved_000; + + // nn::settings::BatteryLot + std::array<u8, 0x18> ptm_battery_lot; + // nn::settings::system::PtmFuelGaugeParameter + std::array<u8, 0x18> ptm_fuel_gauge_parameter; + u8 ptm_battery_version; + // nn::settings::system::PtmCycleCountReliability + u32 ptm_cycle_count_reliability; + + std::array<u8, 0x48> reserved_048; + + // nn::settings::system::AnalogStickUserCalibration L + std::array<u8, 0x10> analog_user_stick_calibration_l; + // nn::settings::system::AnalogStickUserCalibration R + std::array<u8, 0x10> analog_user_stick_calibration_r; + + std::array<u8, 0x20> reserved_0B0; + + // nn::settings::system::ConsoleSixAxisSensorAccelerationBias + std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias + std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias; + // nn::settings::system::ConsoleSixAxisSensorAccelerationGain + std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain + std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias + std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias; + // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration + std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration; +}; +static_assert(offsetof(DeviceSettings, ptm_battery_lot) == 0x10); +static_assert(offsetof(DeviceSettings, ptm_cycle_count_reliability) == 0x44); +static_assert(offsetof(DeviceSettings, analog_user_stick_calibration_l) == 0x90); +static_assert(offsetof(DeviceSettings, console_six_axis_sensor_acceleration_bias) == 0xD0); +static_assert(offsetof(DeviceSettings, console_six_axis_sensor_angular_acceleration) == 0x13C); +static_assert(sizeof(DeviceSettings) == 0x160, "DeviceSettings has the wrong size!"); + +DeviceSettings DefaultDeviceSettings(); + +} // namespace Service::Set diff --git a/src/core/hle/service/set/private_settings.cpp b/src/core/hle/service/set/private_settings.cpp new file mode 100644 index 000000000..70bf65727 --- /dev/null +++ b/src/core/hle/service/set/private_settings.cpp @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/private_settings.h" + +namespace Service::Set { + +PrivateSettings DefaultPrivateSettings() { + return {}; +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/private_settings.h b/src/core/hle/service/set/private_settings.h new file mode 100644 index 000000000..b63eaf45c --- /dev/null +++ b/src/core/hle/service/set/private_settings.h @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/uuid.h" +#include "core/hle/service/time/clock_types.h" + +namespace Service::Set { + +/// This is nn::settings::system::InitialLaunchFlag +struct InitialLaunchFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> InitialLaunchCompletionFlag; + BitField<8, 1, u32> InitialLaunchUserAdditionFlag; + BitField<16, 1, u32> InitialLaunchTimestampFlag; + }; +}; +static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size"); + +/// This is nn::settings::system::InitialLaunchSettings +struct InitialLaunchSettings { + InitialLaunchFlag flags; + INSERT_PADDING_BYTES(0x4); + Service::Time::Clock::SteadyClockTimePoint timestamp; +}; +static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); + +#pragma pack(push, 4) +struct InitialLaunchSettingsPacked { + InitialLaunchFlag flags; + Service::Time::Clock::SteadyClockTimePoint timestamp; +}; +#pragma pack(pop) +static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C, + "InitialLaunchSettingsPacked is incorrect size"); + +struct PrivateSettings { + std::array<u8, 0x10> reserved_00; + + // nn::settings::system::InitialLaunchSettings + InitialLaunchSettings initial_launch_settings; + + std::array<u8, 0x20> reserved_30; + + Common::UUID external_clock_source_id; + s64 shutdown_rtc_value; + s64 external_steady_clock_internal_offset; + + std::array<u8, 0x60> reserved_70; + + // nn::settings::system::PlatformRegion + std::array<u8, 0x4> platform_region; + + std::array<u8, 0x4> reserved_D4; +}; +static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10); +static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50); +static_assert(offsetof(PrivateSettings, reserved_70) == 0x70); +static_assert(offsetof(PrivateSettings, platform_region) == 0xD0); +static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!"); + +PrivateSettings DefaultPrivateSettings(); + +} // namespace Service::Set diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index b61a3560d..6ef3da410 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h @@ -4,35 +4,13 @@ #pragma once #include "core/hle/service/service.h" +#include "core/hle/service/set/system_settings.h" namespace Core { class System; } namespace Service::Set { - -/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. -enum class LanguageCode : u64 { - JA = 0x000000000000616A, - EN_US = 0x00000053552D6E65, - FR = 0x0000000000007266, - DE = 0x0000000000006564, - IT = 0x0000000000007469, - ES = 0x0000000000007365, - ZH_CN = 0x0000004E432D687A, - KO = 0x0000000000006F6B, - NL = 0x0000000000006C6E, - PT = 0x0000000000007470, - RU = 0x0000000000007572, - ZH_TW = 0x00000057542D687A, - EN_GB = 0x00000042472D6E65, - FR_CA = 0x00000041432D7266, - ES_419 = 0x00003931342D7365, - ZH_HANS = 0x00736E61482D687A, - ZH_HANT = 0x00746E61482D687A, - PT_BR = 0x00000052422D7470, -}; - enum class KeyboardLayout : u64 { Japanese = 0, EnglishUs = 1, diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 48304e6d1..0653779d5 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp @@ -1,7 +1,12 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <fstream> + #include "common/assert.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/settings.h" #include "common/string_util.h" @@ -19,6 +24,16 @@ namespace Service::Set { +namespace { +constexpr u32 SETTINGS_VERSION{1u}; +constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't'); +struct SettingsHeader { + u64 magic; + u32 version; + u32 reserved; +}; +} // Anonymous namespace + Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system, GetFirmwareVersionType type) { constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809; @@ -72,11 +87,120 @@ Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& return ResultSuccess; } +bool SET_SYS::LoadSettingsFile(std::filesystem::path& path, auto&& default_func) { + using settings_type = decltype(default_func()); + + if (!Common::FS::CreateDirs(path)) { + return false; + } + + auto settings_file = path / "settings.dat"; + auto exists = std::filesystem::exists(settings_file); + auto file_size_ok = exists && std::filesystem::file_size(settings_file) == + sizeof(SettingsHeader) + sizeof(settings_type); + + auto ResetToDefault = [&]() { + auto default_settings{default_func()}; + + SettingsHeader hdr{ + .magic = SETTINGS_MAGIC, + .version = SETTINGS_VERSION, + .reserved = 0u, + }; + + std::ofstream out_settings_file(settings_file, std::ios::out | std::ios::binary); + out_settings_file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr)); + out_settings_file.write(reinterpret_cast<const char*>(&default_settings), + sizeof(settings_type)); + out_settings_file.flush(); + out_settings_file.close(); + }; + + constexpr auto IsHeaderValid = [](std::ifstream& file) -> bool { + if (!file.is_open()) { + return false; + } + SettingsHeader hdr{}; + file.read(reinterpret_cast<char*>(&hdr), sizeof(hdr)); + return hdr.magic == SETTINGS_MAGIC && hdr.version == SETTINGS_VERSION; + }; + + if (!exists || !file_size_ok) { + ResetToDefault(); + } + + std::ifstream file(settings_file, std::ios::binary | std::ios::in); + if (!IsHeaderValid(file)) { + file.close(); + ResetToDefault(); + file = std::ifstream(settings_file, std::ios::binary | std::ios::in); + if (!IsHeaderValid(file)) { + return false; + } + } + + if constexpr (std::is_same_v<settings_type, PrivateSettings>) { + file.read(reinterpret_cast<char*>(&m_private_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, DeviceSettings>) { + file.read(reinterpret_cast<char*>(&m_device_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, ApplnSettings>) { + file.read(reinterpret_cast<char*>(&m_appln_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, SystemSettings>) { + file.read(reinterpret_cast<char*>(&m_system_settings), sizeof(settings_type)); + } else { + UNREACHABLE(); + } + file.close(); + + return true; +} + +bool SET_SYS::StoreSettingsFile(std::filesystem::path& path, auto& settings) { + using settings_type = std::decay_t<decltype(settings)>; + + if (!Common::FS::IsDir(path)) { + return false; + } + + auto settings_base = path / "settings"; + auto settings_tmp_file = settings_base; + settings_tmp_file = settings_tmp_file.replace_extension("tmp"); + std::ofstream file(settings_tmp_file, std::ios::binary | std::ios::out); + if (!file.is_open()) { + return false; + } + + SettingsHeader hdr{ + .magic = SETTINGS_MAGIC, + .version = SETTINGS_VERSION, + .reserved = 0u, + }; + file.write(reinterpret_cast<const char*>(&hdr), sizeof(hdr)); + + if constexpr (std::is_same_v<settings_type, PrivateSettings>) { + file.write(reinterpret_cast<const char*>(&m_private_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, DeviceSettings>) { + file.write(reinterpret_cast<const char*>(&m_device_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, ApplnSettings>) { + file.write(reinterpret_cast<const char*>(&m_appln_settings), sizeof(settings_type)); + } else if constexpr (std::is_same_v<settings_type, SystemSettings>) { + file.write(reinterpret_cast<const char*>(&m_system_settings), sizeof(settings_type)); + } else { + UNREACHABLE(); + } + file.close(); + + std::filesystem::rename(settings_tmp_file, settings_base.replace_extension("dat")); + + return true; +} + void SET_SYS::SetLanguageCode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - language_code_setting = rp.PopEnum<LanguageCode>(); + m_system_settings.language_code = rp.PopEnum<LanguageCode>(); + SetSaveNeeded(); - LOG_INFO(Service_SET, "called, language_code={}", language_code_setting); + LOG_INFO(Service_SET, "called, language_code={}", m_system_settings.language_code); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -112,19 +236,68 @@ void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) { rb.Push(result); } +void SET_SYS::GetExternalSteadyClockSourceId(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Common::UUID id{}; + auto res = GetExternalSteadyClockSourceId(id); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(Common::UUID) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw(id); +} + +void SET_SYS::SetExternalSteadyClockSourceId(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + auto id{rp.PopRaw<Common::UUID>()}; + + auto res = SetExternalSteadyClockSourceId(id); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void SET_SYS::GetUserSystemClockContext(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Service::Time::Clock::SystemClockContext context{}; + auto res = GetUserSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, + 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw(context); +} + +void SET_SYS::SetUserSystemClockContext(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()}; + + auto res = SetUserSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + void SET_SYS::GetAccountSettings(HLERequestContext& ctx) { LOG_INFO(Service_SET, "called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushRaw(account_settings); + rb.PushRaw(m_system_settings.account_settings); } void SET_SYS::SetAccountSettings(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - account_settings = rp.PopRaw<AccountSettings>(); + m_system_settings.account_settings = rp.PopRaw<AccountSettings>(); + SetSaveNeeded(); - LOG_INFO(Service_SET, "called, account_settings_flags={}", account_settings.flags); + LOG_INFO(Service_SET, "called, account_settings_flags={}", + m_system_settings.account_settings.flags); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -133,11 +306,11 @@ void SET_SYS::SetAccountSettings(HLERequestContext& ctx) { void SET_SYS::GetEulaVersions(HLERequestContext& ctx) { LOG_INFO(Service_SET, "called"); - ctx.WriteBuffer(eula_versions); + ctx.WriteBuffer(m_system_settings.eula_versions); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(static_cast<u32>(eula_versions.size())); + rb.Push(m_system_settings.eula_version_count); } void SET_SYS::SetEulaVersions(HLERequestContext& ctx) { @@ -145,13 +318,12 @@ void SET_SYS::SetEulaVersions(HLERequestContext& ctx) { const auto buffer_data = ctx.ReadBuffer(); LOG_INFO(Service_SET, "called, elements={}", elements); + ASSERT(elements <= m_system_settings.eula_versions.size()); - eula_versions.resize(elements); - for (std::size_t index = 0; index < elements; index++) { - const std::size_t start_index = index * sizeof(EulaVersion); - memcpy(eula_versions.data() + start_index, buffer_data.data() + start_index, - sizeof(EulaVersion)); - } + m_system_settings.eula_version_count = static_cast<u32>(elements); + std::memcpy(&m_system_settings.eula_versions, buffer_data.data(), + sizeof(EulaVersion) * elements); + SetSaveNeeded(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -162,14 +334,15 @@ void SET_SYS::GetColorSetId(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(color_set); + rb.PushEnum(m_system_settings.color_set_id); } void SET_SYS::SetColorSetId(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - color_set = rp.PopEnum<ColorSet>(); + m_system_settings.color_set_id = rp.PopEnum<ColorSet>(); + SetSaveNeeded(); - LOG_DEBUG(Service_SET, "called, color_set={}", color_set); + LOG_DEBUG(Service_SET, "called, color_set={}", m_system_settings.color_set_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -180,17 +353,21 @@ void SET_SYS::GetNotificationSettings(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 8}; rb.Push(ResultSuccess); - rb.PushRaw(notification_settings); + rb.PushRaw(m_system_settings.notification_settings); } void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - notification_settings = rp.PopRaw<NotificationSettings>(); + m_system_settings.notification_settings = rp.PopRaw<NotificationSettings>(); + SetSaveNeeded(); LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}", - notification_settings.flags.raw, notification_settings.volume, - notification_settings.start_time.hour, notification_settings.start_time.minute, - notification_settings.stop_time.hour, notification_settings.stop_time.minute); + m_system_settings.notification_settings.flags.raw, + m_system_settings.notification_settings.volume, + m_system_settings.notification_settings.start_time.hour, + m_system_settings.notification_settings.start_time.minute, + m_system_settings.notification_settings.stop_time.hour, + m_system_settings.notification_settings.stop_time.minute); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -199,11 +376,11 @@ void SET_SYS::SetNotificationSettings(HLERequestContext& ctx) { void SET_SYS::GetAccountNotificationSettings(HLERequestContext& ctx) { LOG_INFO(Service_SET, "called"); - ctx.WriteBuffer(account_notifications); + ctx.WriteBuffer(m_system_settings.account_notification_settings); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(static_cast<u32>(account_notifications.size())); + rb.Push(m_system_settings.account_notification_settings_count); } void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) { @@ -212,12 +389,12 @@ void SET_SYS::SetAccountNotificationSettings(HLERequestContext& ctx) { LOG_INFO(Service_SET, "called, elements={}", elements); - account_notifications.resize(elements); - for (std::size_t index = 0; index < elements; index++) { - const std::size_t start_index = index * sizeof(AccountNotificationSettings); - memcpy(account_notifications.data() + start_index, buffer_data.data() + start_index, - sizeof(AccountNotificationSettings)); - } + ASSERT(elements <= m_system_settings.account_notification_settings.size()); + + m_system_settings.account_notification_settings_count = static_cast<u32>(elements); + std::memcpy(&m_system_settings.account_notification_settings, buffer_data.data(), + elements * sizeof(AccountNotificationSettings)); + SetSaveNeeded(); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -244,6 +421,14 @@ static Settings GetSettings() { ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0}); ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000}); + // Time + ret["time"]["notify_time_to_fs_interval_seconds"] = ToBytes(s32{600}); + ret["time"]["standard_network_clock_sufficient_accuracy_minutes"] = + ToBytes(s32{43200}); // 30 days + ret["time"]["standard_steady_clock_rtc_update_interval_minutes"] = ToBytes(s32{5}); + ret["time"]["standard_steady_clock_test_offset_minutes"] = ToBytes(s32{0}); + ret["time"]["standard_user_clock_initial_year"] = ToBytes(s32{2023}); + return ret; } @@ -273,8 +458,6 @@ void SET_SYS::GetSettingsItemValueSize(HLERequestContext& ctx) { } void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) { - LOG_DEBUG(Service_SET, "called"); - // The category of the setting. This corresponds to the top-level keys of // system_settings.ini. const auto setting_category_buf{ctx.ReadBuffer(0)}; @@ -285,14 +468,13 @@ void SET_SYS::GetSettingsItemValue(HLERequestContext& ctx) { const auto setting_name_buf{ctx.ReadBuffer(1)}; const std::string setting_name{setting_name_buf.begin(), setting_name_buf.end()}; - auto settings{GetSettings()}; - Result response{ResultUnknown}; + std::vector<u8> value; + auto response = GetSettingsItemValue(value, setting_category, setting_name); - if (settings.contains(setting_category) && settings[setting_category].contains(setting_name)) { - auto setting_value = settings[setting_category][setting_name]; - ctx.WriteBuffer(setting_value.data(), setting_value.size()); - response = ResultSuccess; - } + LOG_INFO(Service_SET, "called. category={}, name={} -- res=0x{:X}", setting_category, + setting_name, response.raw); + + ctx.WriteBuffer(value.data(), value.size()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(response); @@ -303,19 +485,23 @@ void SET_SYS::GetTvSettings(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 10}; rb.Push(ResultSuccess); - rb.PushRaw(tv_settings); + rb.PushRaw(m_system_settings.tv_settings); } void SET_SYS::SetTvSettings(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - tv_settings = rp.PopRaw<TvSettings>(); + m_system_settings.tv_settings = rp.PopRaw<TvSettings>(); + SetSaveNeeded(); LOG_INFO(Service_SET, "called, flags={}, cmu_mode={}, constrast_ratio={}, hdmi_content_type={}, " "rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}", - tv_settings.flags.raw, tv_settings.cmu_mode, tv_settings.constrast_ratio, - tv_settings.hdmi_content_type, tv_settings.rgb_range, tv_settings.tv_gama, - tv_settings.tv_resolution, tv_settings.tv_underscan); + m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode, + m_system_settings.tv_settings.constrast_ratio, + m_system_settings.tv_settings.hdmi_content_type, + m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama, + m_system_settings.tv_settings.tv_resolution, + m_system_settings.tv_settings.tv_underscan); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -329,16 +515,87 @@ void SET_SYS::GetQuestFlag(HLERequestContext& ctx) { rb.PushEnum(QuestFlag::Retail); } +void SET_SYS::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) { + LOG_WARNING(Service_SET, "called"); + + Service::Time::TimeZone::LocationName name{}; + auto res = GetDeviceTimeZoneLocationName(name); + + IPC::ResponseBuilder rb{ctx, 2 + sizeof(Service::Time::TimeZone::LocationName) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw<Service::Time::TimeZone::LocationName>(name); +} + +void SET_SYS::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) { + LOG_WARNING(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()}; + + auto res = SetDeviceTimeZoneLocationName(name); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + void SET_SYS::SetRegionCode(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - region_code = rp.PopEnum<RegionCode>(); + m_system_settings.region_code = rp.PopEnum<RegionCode>(); + SetSaveNeeded(); - LOG_INFO(Service_SET, "called, region_code={}", region_code); + LOG_INFO(Service_SET, "called, region_code={}", m_system_settings.region_code); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } +void SET_SYS::GetNetworkSystemClockContext(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + Service::Time::Clock::SystemClockContext context{}; + auto res = GetNetworkSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, + 2 + sizeof(Service::Time::Clock::SystemClockContext) / sizeof(u32)}; + rb.Push(res); + rb.PushRaw(context); +} + +void SET_SYS::SetNetworkSystemClockContext(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + auto context{rp.PopRaw<Service::Time::Clock::SystemClockContext>()}; + + auto res = SetNetworkSystemClockContext(context); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + bool enabled{}; + auto res = IsUserSystemClockAutomaticCorrectionEnabled(enabled); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(res); + rb.PushRaw(enabled); +} + +void SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx) { + LOG_INFO(Service_SET, "called"); + + IPC::RequestParser rp{ctx}; + auto enabled{rp.Pop<bool>()}; + + auto res = SetUserSystemClockAutomaticCorrectionEnabled(enabled); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + void SET_SYS::GetPrimaryAlbumStorage(HLERequestContext& ctx) { LOG_WARNING(Service_SET, "(STUBBED) called"); @@ -352,16 +609,18 @@ void SET_SYS::GetSleepSettings(HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 5}; rb.Push(ResultSuccess); - rb.PushRaw(sleep_settings); + rb.PushRaw(m_system_settings.sleep_settings); } void SET_SYS::SetSleepSettings(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - sleep_settings = rp.PopRaw<SleepSettings>(); + m_system_settings.sleep_settings = rp.PopRaw<SleepSettings>(); + SetSaveNeeded(); LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}", - sleep_settings.flags.raw, sleep_settings.handheld_sleep_plan, - sleep_settings.console_sleep_plan); + m_system_settings.sleep_settings.flags.raw, + m_system_settings.sleep_settings.handheld_sleep_plan, + m_system_settings.sleep_settings.console_sleep_plan); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -371,15 +630,20 @@ void SET_SYS::GetInitialLaunchSettings(HLERequestContext& ctx) { LOG_INFO(Service_SET, "called"); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(ResultSuccess); - rb.PushRaw(launch_settings); + rb.PushRaw(m_system_settings.initial_launch_settings_packed); } void SET_SYS::SetInitialLaunchSettings(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - launch_settings = rp.PopRaw<InitialLaunchSettings>(); + auto inital_launch_settings = rp.PopRaw<InitialLaunchSettings>(); - LOG_INFO(Service_SET, "called, flags={}, timestamp={}", launch_settings.flags.raw, - launch_settings.timestamp.time_point); + m_system_settings.initial_launch_settings_packed.flags = inital_launch_settings.flags; + m_system_settings.initial_launch_settings_packed.timestamp = inital_launch_settings.timestamp; + SetSaveNeeded(); + + LOG_INFO(Service_SET, "called, flags={}, timestamp={}", + m_system_settings.initial_launch_settings_packed.flags.raw, + m_system_settings.initial_launch_settings_packed.timestamp.time_point); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -437,13 +701,37 @@ void SET_SYS::GetAutoUpdateEnableFlag(HLERequestContext& ctx) { void SET_SYS::GetBatteryPercentageFlag(HLERequestContext& ctx) { u8 battery_percentage_flag{1}; - LOG_DEBUG(Service_SET, "(STUBBED) called, battery_percentage_flag={}", battery_percentage_flag); + LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}", + battery_percentage_flag); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(battery_percentage_flag); } +void SET_SYS::SetExternalSteadyClockInternalOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called."); + + IPC::RequestParser rp{ctx}; + auto offset{rp.Pop<s64>()}; + + auto res = SetExternalSteadyClockInternalOffset(offset); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void SET_SYS::GetExternalSteadyClockInternalOffset(HLERequestContext& ctx) { + LOG_DEBUG(Service_SET, "called."); + + s64 offset{}; + auto res = GetExternalSteadyClockInternalOffset(offset); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.Push(offset); +} + void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) { LOG_WARNING(Service_SET, "(STUBBED) called"); @@ -453,18 +741,19 @@ void SET_SYS::GetErrorReportSharePermission(HLERequestContext& ctx) { } void SET_SYS::GetAppletLaunchFlags(HLERequestContext& ctx) { - LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag); + LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push(applet_launch_flag); + rb.Push(m_system_settings.applet_launch_flag); } void SET_SYS::SetAppletLaunchFlags(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - applet_launch_flag = rp.Pop<u32>(); + m_system_settings.applet_launch_flag = rp.Pop<u32>(); + SetSaveNeeded(); - LOG_INFO(Service_SET, "called, applet_launch_flag={}", applet_launch_flag); + LOG_INFO(Service_SET, "called, applet_launch_flag={}", m_system_settings.applet_launch_flag); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -489,6 +778,52 @@ void SET_SYS::GetKeyboardLayout(HLERequestContext& ctx) { rb.Push(static_cast<u32>(selected_keyboard_layout)); } +void SET_SYS::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { + LOG_WARNING(Service_SET, "called."); + + Service::Time::Clock::SteadyClockTimePoint time_point{}; + auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point); +} + +void SET_SYS::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) { + LOG_WARNING(Service_SET, "called."); + + IPC::RequestParser rp{ctx}; + auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; + + auto res = SetDeviceTimeZoneLocationUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + +void SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx) { + LOG_WARNING(Service_SET, "called."); + + Service::Time::Clock::SteadyClockTimePoint time_point{}; + auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(res); + rb.PushRaw<Service::Time::Clock::SteadyClockTimePoint>(time_point); +} + +void SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx) { + LOG_WARNING(Service_SET, "called."); + + IPC::RequestParser rp{ctx}; + auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()}; + + auto res = SetUserSystemClockAutomaticCorrectionUpdatedTime(time_point); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(res); +} + void SET_SYS::GetChineseTraditionalInputMethod(HLERequestContext& ctx) { LOG_WARNING(Service_SET, "(STUBBED) called"); @@ -508,7 +843,7 @@ void SET_SYS::GetHomeMenuScheme(HLERequestContext& ctx) { .extra = 0xFF000000, }; - IPC::ResponseBuilder rb{ctx, 7}; + IPC::ResponseBuilder rb{ctx, 2 + sizeof(HomeMenuScheme) / sizeof(u32)}; rb.Push(ResultSuccess); rb.PushRaw(default_color); } @@ -520,6 +855,7 @@ void SET_SYS::GetHomeMenuSchemeModel(HLERequestContext& ctx) { rb.Push(ResultSuccess); rb.Push(0); } + void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) { LOG_WARNING(Service_SET, "(STUBBED) called"); @@ -528,7 +864,7 @@ void SET_SYS::GetFieldTestingFlag(HLERequestContext& ctx) { rb.Push<u8>(false); } -SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { +SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"}, m_system{system} { // clang-format off static const FunctionInfo functions[] = { {0, &SET_SYS::SetLanguageCode, "SetLanguageCode"}, @@ -543,10 +879,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { {10, nullptr, "SetBacklightSettings"}, {11, nullptr, "SetBluetoothDevicesSettings"}, {12, nullptr, "GetBluetoothDevicesSettings"}, - {13, nullptr, "GetExternalSteadyClockSourceId"}, - {14, nullptr, "SetExternalSteadyClockSourceId"}, - {15, nullptr, "GetUserSystemClockContext"}, - {16, nullptr, "SetUserSystemClockContext"}, + {13, &SET_SYS::GetExternalSteadyClockSourceId, "GetExternalSteadyClockSourceId"}, + {14, &SET_SYS::SetExternalSteadyClockSourceId, "SetExternalSteadyClockSourceId"}, + {15, &SET_SYS::GetUserSystemClockContext, "GetUserSystemClockContext"}, + {16, &SET_SYS::SetUserSystemClockContext, "SetUserSystemClockContext"}, {17, &SET_SYS::GetAccountSettings, "GetAccountSettings"}, {18, &SET_SYS::SetAccountSettings, "SetAccountSettings"}, {19, nullptr, "GetAudioVolume"}, @@ -581,15 +917,15 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { {50, nullptr, "SetDataDeletionSettings"}, {51, nullptr, "GetInitialSystemAppletProgramId"}, {52, nullptr, "GetOverlayDispProgramId"}, - {53, nullptr, "GetDeviceTimeZoneLocationName"}, - {54, nullptr, "SetDeviceTimeZoneLocationName"}, + {53, &SET_SYS::GetDeviceTimeZoneLocationName, "GetDeviceTimeZoneLocationName"}, + {54, &SET_SYS::SetDeviceTimeZoneLocationName, "SetDeviceTimeZoneLocationName"}, {55, nullptr, "GetWirelessCertificationFileSize"}, {56, nullptr, "GetWirelessCertificationFile"}, {57, &SET_SYS::SetRegionCode, "SetRegionCode"}, - {58, nullptr, "GetNetworkSystemClockContext"}, - {59, nullptr, "SetNetworkSystemClockContext"}, - {60, nullptr, "IsUserSystemClockAutomaticCorrectionEnabled"}, - {61, nullptr, "SetUserSystemClockAutomaticCorrectionEnabled"}, + {58, &SET_SYS::GetNetworkSystemClockContext, "GetNetworkSystemClockContext"}, + {59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"}, + {60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"}, + {61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"}, {62, nullptr, "GetDebugModeFlag"}, {63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"}, {64, nullptr, "SetPrimaryAlbumStorage"}, @@ -633,8 +969,8 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { {102, nullptr, "SetExternalRtcResetFlag"}, {103, nullptr, "GetUsbFullKeyEnableFlag"}, {104, nullptr, "SetUsbFullKeyEnableFlag"}, - {105, nullptr, "SetExternalSteadyClockInternalOffset"}, - {106, nullptr, "GetExternalSteadyClockInternalOffset"}, + {105, &SET_SYS::SetExternalSteadyClockInternalOffset, "SetExternalSteadyClockInternalOffset"}, + {106, &SET_SYS::GetExternalSteadyClockInternalOffset, "GetExternalSteadyClockInternalOffset"}, {107, nullptr, "GetBacklightSettingsEx"}, {108, nullptr, "SetBacklightSettingsEx"}, {109, nullptr, "GetHeadphoneVolumeWarningCount"}, @@ -678,10 +1014,10 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { {147, nullptr, "GetConsoleSixAxisSensorAngularAcceleration"}, {148, nullptr, "SetConsoleSixAxisSensorAngularAcceleration"}, {149, nullptr, "GetRebootlessSystemUpdateVersion"}, - {150, nullptr, "GetDeviceTimeZoneLocationUpdatedTime"}, - {151, nullptr, "SetDeviceTimeZoneLocationUpdatedTime"}, - {152, nullptr, "GetUserSystemClockAutomaticCorrectionUpdatedTime"}, - {153, nullptr, "SetUserSystemClockAutomaticCorrectionUpdatedTime"}, + {150, &SET_SYS::GetDeviceTimeZoneLocationUpdatedTime, "GetDeviceTimeZoneLocationUpdatedTime"}, + {151, &SET_SYS::SetDeviceTimeZoneLocationUpdatedTime, "SetDeviceTimeZoneLocationUpdatedTime"}, + {152, &SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime, "GetUserSystemClockAutomaticCorrectionUpdatedTime"}, + {153, &SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime, "SetUserSystemClockAutomaticCorrectionUpdatedTime"}, {154, nullptr, "GetAccountOnlineStorageSettings"}, {155, nullptr, "SetAccountOnlineStorageSettings"}, {156, nullptr, "GetPctlReadyFlag"}, @@ -743,8 +1079,184 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"} { // clang-format on RegisterHandlers(functions); + + SetupSettings(); + m_save_thread = + std::jthread([this](std::stop_token stop_token) { StoreSettingsThreadFunc(stop_token); }); +} + +SET_SYS::~SET_SYS() { + SetSaveNeeded(); + m_save_thread.request_stop(); +} + +void SET_SYS::SetupSettings() { + auto system_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; + if (!LoadSettingsFile(system_dir, []() { return DefaultSystemSettings(); })) { + ASSERT(false); + } + + auto private_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; + if (!LoadSettingsFile(private_dir, []() { return DefaultPrivateSettings(); })) { + ASSERT(false); + } + + auto device_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; + if (!LoadSettingsFile(device_dir, []() { return DefaultDeviceSettings(); })) { + ASSERT(false); + } + + auto appln_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; + if (!LoadSettingsFile(appln_dir, []() { return DefaultApplnSettings(); })) { + ASSERT(false); + } +} + +void SET_SYS::StoreSettings() { + auto system_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000050"; + if (!StoreSettingsFile(system_dir, m_system_settings)) { + LOG_ERROR(HW_GPU, "Failed to store System settings"); + } + + auto private_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000052"; + if (!StoreSettingsFile(private_dir, m_private_settings)) { + LOG_ERROR(HW_GPU, "Failed to store Private settings"); + } + + auto device_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000053"; + if (!StoreSettingsFile(device_dir, m_device_settings)) { + LOG_ERROR(HW_GPU, "Failed to store Device settings"); + } + + auto appln_dir = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000054"; + if (!StoreSettingsFile(appln_dir, m_appln_settings)) { + LOG_ERROR(HW_GPU, "Failed to store ApplLn settings"); + } +} + +void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) { + while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) { + std::scoped_lock l{m_save_needed_mutex}; + if (!std::exchange(m_save_needed, false)) { + continue; + } + StoreSettings(); + } +} + +void SET_SYS::SetSaveNeeded() { + std::scoped_lock l{m_save_needed_mutex}; + m_save_needed = true; +} + +Result SET_SYS::GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category, + const std::string& name) { + auto settings{GetSettings()}; + R_UNLESS(settings.contains(category) && settings[category].contains(name), ResultUnknown); + + out_value = settings[category][name]; + R_SUCCEED(); +} + +Result SET_SYS::GetExternalSteadyClockSourceId(Common::UUID& out_id) { + out_id = m_private_settings.external_clock_source_id; + R_SUCCEED(); +} + +Result SET_SYS::SetExternalSteadyClockSourceId(Common::UUID id) { + m_private_settings.external_clock_source_id = id; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result SET_SYS::GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context) { + out_context = m_system_settings.user_system_clock_context; + R_SUCCEED(); } -SET_SYS::~SET_SYS() = default; +Result SET_SYS::SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context) { + m_system_settings.user_system_clock_context = context; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result SET_SYS::GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name) { + out_name = m_system_settings.device_time_zone_location_name; + R_SUCCEED(); +} + +Result SET_SYS::SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name) { + m_system_settings.device_time_zone_location_name = name; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result SET_SYS::GetNetworkSystemClockContext( + Service::Time::Clock::SystemClockContext& out_context) { + out_context = m_system_settings.network_system_clock_context; + R_SUCCEED(); +} + +Result SET_SYS::SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context) { + m_system_settings.network_system_clock_context = context; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled) { + out_enabled = m_system_settings.user_system_clock_automatic_correction_enabled; + R_SUCCEED(); +} + +Result SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled(bool enabled) { + m_system_settings.user_system_clock_automatic_correction_enabled = enabled; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result SET_SYS::SetExternalSteadyClockInternalOffset(s64 offset) { + m_private_settings.external_steady_clock_internal_offset = offset; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result SET_SYS::GetExternalSteadyClockInternalOffset(s64& out_offset) { + out_offset = m_private_settings.external_steady_clock_internal_offset; + R_SUCCEED(); +} + +Result SET_SYS::GetDeviceTimeZoneLocationUpdatedTime( + Service::Time::Clock::SteadyClockTimePoint& out_time_point) { + out_time_point = m_system_settings.device_time_zone_location_updated_time; + R_SUCCEED(); +} + +Result SET_SYS::SetDeviceTimeZoneLocationUpdatedTime( + Service::Time::Clock::SteadyClockTimePoint& time_point) { + m_system_settings.device_time_zone_location_updated_time = time_point; + SetSaveNeeded(); + R_SUCCEED(); +} + +Result SET_SYS::GetUserSystemClockAutomaticCorrectionUpdatedTime( + Service::Time::Clock::SteadyClockTimePoint& out_time_point) { + out_time_point = m_system_settings.user_system_clock_automatic_correction_updated_time_point; + R_SUCCEED(); +} + +Result SET_SYS::SetUserSystemClockAutomaticCorrectionUpdatedTime( + Service::Time::Clock::SteadyClockTimePoint out_time_point) { + m_system_settings.user_system_clock_automatic_correction_updated_time_point = out_time_point; + SetSaveNeeded(); + R_SUCCEED(); +} } // namespace Service::Set diff --git a/src/core/hle/service/set/set_sys.h b/src/core/hle/service/set/set_sys.h index 5f770fd32..3785d93d8 100644 --- a/src/core/hle/service/set/set_sys.h +++ b/src/core/hle/service/set/set_sys.h @@ -3,17 +3,27 @@ #pragma once +#include <filesystem> +#include <mutex> +#include <string> +#include <thread> + +#include "common/polyfill_thread.h" #include "common/uuid.h" #include "core/hle/result.h" #include "core/hle/service/service.h" +#include "core/hle/service/set/appln_settings.h" +#include "core/hle/service/set/device_settings.h" +#include "core/hle/service/set/private_settings.h" +#include "core/hle/service/set/system_settings.h" #include "core/hle/service/time/clock_types.h" +#include "core/hle/service/time/time_zone_types.h" namespace Core { class System; } namespace Service::Set { -enum class LanguageCode : u64; enum class GetFirmwareVersionType { Version1, Version2, @@ -42,270 +52,38 @@ public: explicit SET_SYS(Core::System& system_); ~SET_SYS() override; -private: - /// Indicates the current theme set by the system settings - enum class ColorSet : u32 { - BasicWhite = 0, - BasicBlack = 1, - }; - - /// Indicates the current console is a retail or kiosk unit - enum class QuestFlag : u8 { - Retail = 0, - Kiosk = 1, - }; - - /// This is nn::settings::system::TvResolution - enum class TvResolution : u32 { - Auto, - Resolution1080p, - Resolution720p, - Resolution480p, - }; - - /// This is nn::settings::system::HdmiContentType - enum class HdmiContentType : u32 { - None, - Graphics, - Cinema, - Photo, - Game, - }; - - /// This is nn::settings::system::RgbRange - enum class RgbRange : u32 { - Auto, - Full, - Limited, - }; - - /// This is nn::settings::system::CmuMode - enum class CmuMode : u32 { - None, - ColorInvert, - HighContrast, - GrayScale, - }; - - /// This is nn::settings::system::PrimaryAlbumStorage - enum class PrimaryAlbumStorage : u32 { - Nand, - SdCard, - }; - - /// This is nn::settings::system::NotificationVolume - enum class NotificationVolume : u32 { - Mute, - Low, - High, - }; - - /// This is nn::settings::system::ChineseTraditionalInputMethod - enum class ChineseTraditionalInputMethod : u32 { - Unknown0 = 0, - Unknown1 = 1, - Unknown2 = 2, - }; - - /// This is nn::settings::system::ErrorReportSharePermission - enum class ErrorReportSharePermission : u32 { - NotConfirmed, - Granted, - Denied, - }; - - /// This is nn::settings::system::FriendPresenceOverlayPermission - enum class FriendPresenceOverlayPermission : u8 { - NotConfirmed, - NoDisplay, - FavoriteFriends, - Friends, - }; - - /// This is nn::settings::system::HandheldSleepPlan - enum class HandheldSleepPlan : u32 { - Sleep1Min, - Sleep3Min, - Sleep5Min, - Sleep10Min, - Sleep30Min, - Never, - }; - - /// This is nn::settings::system::ConsoleSleepPlan - enum class ConsoleSleepPlan : u32 { - Sleep1Hour, - Sleep2Hour, - Sleep3Hour, - Sleep6Hour, - Sleep12Hour, - Never, - }; - - /// This is nn::settings::system::RegionCode - enum class RegionCode : u32 { - Japan, - Usa, - Europe, - Australia, - HongKongTaiwanKorea, - China, - }; - - /// This is nn::settings::system::EulaVersionClockType - enum class EulaVersionClockType : u32 { - NetworkSystemClock, - SteadyClock, - }; - - /// This is nn::settings::system::SleepFlag - struct SleepFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> SleepsWhilePlayingMedia; - BitField<1, 1, u32> WakesAtPowerStateChange; - }; - }; - static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size"); - - /// This is nn::settings::system::TvFlag - struct TvFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> Allows4k; - BitField<1, 1, u32> Allows3d; - BitField<2, 1, u32> AllowsCec; - BitField<3, 1, u32> PreventsScreenBurnIn; - }; - }; - static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size"); - - /// This is nn::settings::system::InitialLaunchFlag - struct InitialLaunchFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> InitialLaunchCompletionFlag; - BitField<8, 1, u32> InitialLaunchUserAdditionFlag; - BitField<16, 1, u32> InitialLaunchTimestampFlag; - }; - }; - static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size"); - - /// This is nn::settings::system::NotificationFlag - struct NotificationFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> RingtoneFlag; - BitField<1, 1, u32> DownloadCompletionFlag; - BitField<8, 1, u32> EnablesNews; - BitField<9, 1, u32> IncomingLampFlag; - }; - }; - static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size"); - - /// This is nn::settings::system::AccountNotificationFlag - struct AccountNotificationFlag { - union { - u32 raw{}; - - BitField<0, 1, u32> FriendOnlineFlag; - BitField<1, 1, u32> FriendRequestFlag; - BitField<8, 1, u32> CoralInvitationFlag; - }; - }; - static_assert(sizeof(AccountNotificationFlag) == 4, - "AccountNotificationFlag is an invalid size"); - - /// This is nn::settings::system::TvSettings - struct TvSettings { - TvFlag flags; - TvResolution tv_resolution; - HdmiContentType hdmi_content_type; - RgbRange rgb_range; - CmuMode cmu_mode; - u32 tv_underscan; - f32 tv_gama; - f32 constrast_ratio; - }; - static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); - - /// This is nn::settings::system::NotificationTime - struct NotificationTime { - u32 hour; - u32 minute; - }; - static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size"); - - /// This is nn::settings::system::NotificationSettings - struct NotificationSettings { - NotificationFlag flags; - NotificationVolume volume; - NotificationTime start_time; - NotificationTime stop_time; - }; - static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size"); - - /// This is nn::settings::system::AccountSettings - struct AccountSettings { - u32 flags; - }; - static_assert(sizeof(AccountSettings) == 0x4, "AccountSettings is an invalid size"); - - /// This is nn::settings::system::AccountNotificationSettings - struct AccountNotificationSettings { - Common::UUID uid; - AccountNotificationFlag flags; - FriendPresenceOverlayPermission friend_presence_permission; - FriendPresenceOverlayPermission friend_invitation_permission; - INSERT_PADDING_BYTES(0x2); - }; - static_assert(sizeof(AccountNotificationSettings) == 0x18, - "AccountNotificationSettings is an invalid size"); - - /// This is nn::settings::system::InitialLaunchSettings - struct SleepSettings { - SleepFlag flags; - HandheldSleepPlan handheld_sleep_plan; - ConsoleSleepPlan console_sleep_plan; - }; - static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size"); - - /// This is nn::settings::system::InitialLaunchSettings - struct InitialLaunchSettings { - InitialLaunchFlag flags; - INSERT_PADDING_BYTES(0x4); - Time::Clock::SteadyClockTimePoint timestamp; - }; - static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size"); - - /// This is nn::settings::system::InitialLaunchSettings - struct EulaVersion { - u32 version; - RegionCode region_code; - EulaVersionClockType clock_type; - INSERT_PADDING_BYTES(0x4); - s64 posix_time; - Time::Clock::SteadyClockTimePoint timestamp; - }; - static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); - - /// This is nn::settings::system::HomeMenuScheme - struct HomeMenuScheme { - u32 main; - u32 back; - u32 sub; - u32 bezel; - u32 extra; - }; - static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size"); + Result GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category, + const std::string& name); + + Result GetExternalSteadyClockSourceId(Common::UUID& out_id); + Result SetExternalSteadyClockSourceId(Common::UUID id); + Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); + Result SetUserSystemClockContext(Service::Time::Clock::SystemClockContext& context); + Result GetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& out_name); + Result SetDeviceTimeZoneLocationName(Service::Time::TimeZone::LocationName& name); + Result GetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& out_context); + Result SetNetworkSystemClockContext(Service::Time::Clock::SystemClockContext& context); + Result IsUserSystemClockAutomaticCorrectionEnabled(bool& out_enabled); + Result SetUserSystemClockAutomaticCorrectionEnabled(bool enabled); + Result SetExternalSteadyClockInternalOffset(s64 offset); + Result GetExternalSteadyClockInternalOffset(s64& out_offset); + Result GetDeviceTimeZoneLocationUpdatedTime( + Service::Time::Clock::SteadyClockTimePoint& out_time_point); + Result SetDeviceTimeZoneLocationUpdatedTime( + Service::Time::Clock::SteadyClockTimePoint& time_point); + Result GetUserSystemClockAutomaticCorrectionUpdatedTime( + Service::Time::Clock::SteadyClockTimePoint& out_time_point); + Result SetUserSystemClockAutomaticCorrectionUpdatedTime( + Service::Time::Clock::SteadyClockTimePoint time_point); +private: void SetLanguageCode(HLERequestContext& ctx); void GetFirmwareVersion(HLERequestContext& ctx); void GetFirmwareVersion2(HLERequestContext& ctx); + void GetExternalSteadyClockSourceId(HLERequestContext& ctx); + void SetExternalSteadyClockSourceId(HLERequestContext& ctx); + void GetUserSystemClockContext(HLERequestContext& ctx); + void SetUserSystemClockContext(HLERequestContext& ctx); void GetAccountSettings(HLERequestContext& ctx); void SetAccountSettings(HLERequestContext& ctx); void GetEulaVersions(HLERequestContext& ctx); @@ -321,7 +99,13 @@ private: void GetTvSettings(HLERequestContext& ctx); void SetTvSettings(HLERequestContext& ctx); void GetQuestFlag(HLERequestContext& ctx); + void GetDeviceTimeZoneLocationName(HLERequestContext& ctx); + void SetDeviceTimeZoneLocationName(HLERequestContext& ctx); void SetRegionCode(HLERequestContext& ctx); + void GetNetworkSystemClockContext(HLERequestContext& ctx); + void SetNetworkSystemClockContext(HLERequestContext& ctx); + void IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); + void SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx); void GetPrimaryAlbumStorage(HLERequestContext& ctx); void GetSleepSettings(HLERequestContext& ctx); void SetSleepSettings(HLERequestContext& ctx); @@ -333,59 +117,36 @@ private: void GetMiiAuthorId(HLERequestContext& ctx); void GetAutoUpdateEnableFlag(HLERequestContext& ctx); void GetBatteryPercentageFlag(HLERequestContext& ctx); + void SetExternalSteadyClockInternalOffset(HLERequestContext& ctx); + void GetExternalSteadyClockInternalOffset(HLERequestContext& ctx); void GetErrorReportSharePermission(HLERequestContext& ctx); void GetAppletLaunchFlags(HLERequestContext& ctx); void SetAppletLaunchFlags(HLERequestContext& ctx); void GetKeyboardLayout(HLERequestContext& ctx); + void GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx); + void SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx); + void GetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); + void SetUserSystemClockAutomaticCorrectionUpdatedTime(HLERequestContext& ctx); void GetChineseTraditionalInputMethod(HLERequestContext& ctx); - void GetFieldTestingFlag(HLERequestContext& ctx); void GetHomeMenuScheme(HLERequestContext& ctx); void GetHomeMenuSchemeModel(HLERequestContext& ctx); + void GetFieldTestingFlag(HLERequestContext& ctx); - AccountSettings account_settings{ - .flags = {}, - }; - - ColorSet color_set = ColorSet::BasicWhite; - - NotificationSettings notification_settings{ - .flags = {0x300}, - .volume = NotificationVolume::High, - .start_time = {.hour = 9, .minute = 0}, - .stop_time = {.hour = 21, .minute = 0}, - }; - - std::vector<AccountNotificationSettings> account_notifications{}; - - TvSettings tv_settings{ - .flags = {0xc}, - .tv_resolution = TvResolution::Auto, - .hdmi_content_type = HdmiContentType::Game, - .rgb_range = RgbRange::Auto, - .cmu_mode = CmuMode::None, - .tv_underscan = {}, - .tv_gama = 1.0f, - .constrast_ratio = 0.5f, - }; - - InitialLaunchSettings launch_settings{ - .flags = {0x10001}, - .timestamp = {}, - }; - - SleepSettings sleep_settings{ - .flags = {0x3}, - .handheld_sleep_plan = HandheldSleepPlan::Sleep10Min, - .console_sleep_plan = ConsoleSleepPlan::Sleep1Hour, - }; - - u32 applet_launch_flag{}; - - std::vector<EulaVersion> eula_versions{}; - - RegionCode region_code; - - LanguageCode language_code_setting; + bool LoadSettingsFile(std::filesystem::path& path, auto&& default_func); + bool StoreSettingsFile(std::filesystem::path& path, auto& settings); + void SetupSettings(); + void StoreSettings(); + void StoreSettingsThreadFunc(std::stop_token stop_token); + void SetSaveNeeded(); + + Core::System& m_system; + SystemSettings m_system_settings{}; + PrivateSettings m_private_settings{}; + DeviceSettings m_device_settings{}; + ApplnSettings m_appln_settings{}; + std::jthread m_save_thread; + std::mutex m_save_needed_mutex; + bool m_save_needed{false}; }; } // namespace Service::Set diff --git a/src/core/hle/service/set/system_settings.cpp b/src/core/hle/service/set/system_settings.cpp new file mode 100644 index 000000000..2723417ad --- /dev/null +++ b/src/core/hle/service/set/system_settings.cpp @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/hle/service/set/system_settings.h" + +namespace Service::Set { + +SystemSettings DefaultSystemSettings() { + SystemSettings settings{}; + + settings.version = 0x140000; + settings.flags = 7; + + settings.color_set_id = ColorSet::BasicWhite; + + settings.notification_settings = { + .flags{0x300}, + .volume = NotificationVolume::High, + .start_time = {.hour = 9, .minute = 0}, + .stop_time = {.hour = 21, .minute = 0}, + }; + + settings.tv_settings = { + .flags = {0xC}, + .tv_resolution = TvResolution::Auto, + .hdmi_content_type = HdmiContentType::Game, + .rgb_range = RgbRange::Auto, + .cmu_mode = CmuMode::None, + .tv_underscan = {}, + .tv_gama = 1.0f, + .constrast_ratio = 0.5f, + }; + + settings.initial_launch_settings_packed = { + .flags = {0x10001}, + .timestamp = {}, + }; + + settings.sleep_settings = { + .flags = {0x3}, + .handheld_sleep_plan = HandheldSleepPlan::Sleep10Min, + .console_sleep_plan = ConsoleSleepPlan::Sleep1Hour, + }; + + settings.device_time_zone_location_name = {"UTC"}; + settings.user_system_clock_automatic_correction_enabled = false; + + return settings; +} + +} // namespace Service::Set diff --git a/src/core/hle/service/set/system_settings.h b/src/core/hle/service/set/system_settings.h new file mode 100644 index 000000000..ded2906ad --- /dev/null +++ b/src/core/hle/service/set/system_settings.h @@ -0,0 +1,699 @@ +// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/service/set/private_settings.h" +#include "core/hle/service/time/clock_types.h" + +namespace Service::Set { + +/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64. +enum class LanguageCode : u64 { + JA = 0x000000000000616A, + EN_US = 0x00000053552D6E65, + FR = 0x0000000000007266, + DE = 0x0000000000006564, + IT = 0x0000000000007469, + ES = 0x0000000000007365, + ZH_CN = 0x0000004E432D687A, + KO = 0x0000000000006F6B, + NL = 0x0000000000006C6E, + PT = 0x0000000000007470, + RU = 0x0000000000007572, + ZH_TW = 0x00000057542D687A, + EN_GB = 0x00000042472D6E65, + FR_CA = 0x00000041432D7266, + ES_419 = 0x00003931342D7365, + ZH_HANS = 0x00736E61482D687A, + ZH_HANT = 0x00746E61482D687A, + PT_BR = 0x00000052422D7470, +}; + +/// This is nn::settings::system::ErrorReportSharePermission +enum class ErrorReportSharePermission : u32 { + NotConfirmed, + Granted, + Denied, +}; + +/// This is nn::settings::system::ChineseTraditionalInputMethod +enum class ChineseTraditionalInputMethod : u32 { + Unknown0 = 0, + Unknown1 = 1, + Unknown2 = 2, +}; + +/// This is nn::settings::system::HomeMenuScheme +struct HomeMenuScheme { + u32 main; + u32 back; + u32 sub; + u32 bezel; + u32 extra; +}; +static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size"); + +/// Indicates the current theme set by the system settings +enum class ColorSet : u32 { + BasicWhite = 0, + BasicBlack = 1, +}; + +/// Indicates the current console is a retail or kiosk unit +enum class QuestFlag : u8 { + Retail = 0, + Kiosk = 1, +}; + +/// This is nn::settings::system::RegionCode +enum class RegionCode : u32 { + Japan, + Usa, + Europe, + Australia, + HongKongTaiwanKorea, + China, +}; + +/// This is nn::settings::system::AccountSettings +struct AccountSettings { + u32 flags; +}; +static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size"); + +/// This is nn::settings::system::NotificationVolume +enum class NotificationVolume : u32 { + Mute, + Low, + High, +}; + +/// This is nn::settings::system::NotificationFlag +struct NotificationFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> RingtoneFlag; + BitField<1, 1, u32> DownloadCompletionFlag; + BitField<8, 1, u32> EnablesNews; + BitField<9, 1, u32> IncomingLampFlag; + }; +}; +static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size"); + +/// This is nn::settings::system::NotificationTime +struct NotificationTime { + u32 hour; + u32 minute; +}; +static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size"); + +/// This is nn::settings::system::NotificationSettings +struct NotificationSettings { + NotificationFlag flags; + NotificationVolume volume; + NotificationTime start_time; + NotificationTime stop_time; +}; +static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size"); + +/// This is nn::settings::system::AccountNotificationFlag +struct AccountNotificationFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> FriendOnlineFlag; + BitField<1, 1, u32> FriendRequestFlag; + BitField<8, 1, u32> CoralInvitationFlag; + }; +}; +static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size"); + +/// This is nn::settings::system::FriendPresenceOverlayPermission +enum class FriendPresenceOverlayPermission : u8 { + NotConfirmed, + NoDisplay, + FavoriteFriends, + Friends, +}; + +/// This is nn::settings::system::AccountNotificationSettings +struct AccountNotificationSettings { + Common::UUID uid; + AccountNotificationFlag flags; + FriendPresenceOverlayPermission friend_presence_permission; + FriendPresenceOverlayPermission friend_invitation_permission; + INSERT_PADDING_BYTES(0x2); +}; +static_assert(sizeof(AccountNotificationSettings) == 0x18, + "AccountNotificationSettings is an invalid size"); + +/// This is nn::settings::system::TvFlag +struct TvFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> Allows4k; + BitField<1, 1, u32> Allows3d; + BitField<2, 1, u32> AllowsCec; + BitField<3, 1, u32> PreventsScreenBurnIn; + }; +}; +static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size"); + +/// This is nn::settings::system::TvResolution +enum class TvResolution : u32 { + Auto, + Resolution1080p, + Resolution720p, + Resolution480p, +}; + +/// This is nn::settings::system::HdmiContentType +enum class HdmiContentType : u32 { + None, + Graphics, + Cinema, + Photo, + Game, +}; + +/// This is nn::settings::system::RgbRange +enum class RgbRange : u32 { + Auto, + Full, + Limited, +}; + +/// This is nn::settings::system::CmuMode +enum class CmuMode : u32 { + None, + ColorInvert, + HighContrast, + GrayScale, +}; + +/// This is nn::settings::system::TvSettings +struct TvSettings { + TvFlag flags; + TvResolution tv_resolution; + HdmiContentType hdmi_content_type; + RgbRange rgb_range; + CmuMode cmu_mode; + u32 tv_underscan; + f32 tv_gama; + f32 constrast_ratio; +}; +static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size"); + +/// This is nn::settings::system::PrimaryAlbumStorage +enum class PrimaryAlbumStorage : u32 { + Nand, + SdCard, +}; + +/// This is nn::settings::system::HandheldSleepPlan +enum class HandheldSleepPlan : u32 { + Sleep1Min, + Sleep3Min, + Sleep5Min, + Sleep10Min, + Sleep30Min, + Never, +}; + +/// This is nn::settings::system::ConsoleSleepPlan +enum class ConsoleSleepPlan : u32 { + Sleep1Hour, + Sleep2Hour, + Sleep3Hour, + Sleep6Hour, + Sleep12Hour, + Never, +}; + +/// This is nn::settings::system::SleepFlag +struct SleepFlag { + union { + u32 raw{}; + + BitField<0, 1, u32> SleepsWhilePlayingMedia; + BitField<1, 1, u32> WakesAtPowerStateChange; + }; +}; +static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size"); + +/// This is nn::settings::system::SleepSettings +struct SleepSettings { + SleepFlag flags; + HandheldSleepPlan handheld_sleep_plan; + ConsoleSleepPlan console_sleep_plan; +}; +static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size"); + +/// This is nn::settings::system::EulaVersionClockType +enum class EulaVersionClockType : u32 { + NetworkSystemClock, + SteadyClock, +}; + +/// This is nn::settings::system::EulaVersion +struct EulaVersion { + u32 version; + RegionCode region_code; + EulaVersionClockType clock_type; + INSERT_PADDING_BYTES(0x4); + s64 posix_time; + Time::Clock::SteadyClockTimePoint timestamp; +}; +static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size"); + +struct SystemSettings { + // 0/unwritten (1.0.0), 0x20000 (2.0.0), 0x30000 (3.0.0-3.0.1), 0x40001 (4.0.0-4.1.0), 0x50000 + // (5.0.0-5.1.0), 0x60000 (6.0.0-6.2.0), 0x70000 (7.0.0), 0x80000 (8.0.0-8.1.1), 0x90000 + // (9.0.0-10.0.4), 0x100100 (10.1.0+), 0x120000 (12.0.0-12.1.0), 0x130000 (13.0.0-13.2.1), + // 0x140000 (14.0.0+) + u32 version; + // 0/unwritten (1.0.0), 1 (6.0.0-8.1.0), 2 (8.1.1), 7 (9.0.0+). + // if (flags & 2), defaults are written for AnalogStickUserCalibration + u32 flags; + + std::array<u8, 0x8> reserved_00008; + + // nn::settings::LanguageCode + LanguageCode language_code; + + std::array<u8, 0x38> reserved_00018; + + // nn::settings::system::NetworkSettings + u32 network_setting_count; + bool wireless_lan_enable_flag; + std::array<u8, 0x3> pad_00055; + + std::array<u8, 0x8> reserved_00058; + + // nn::settings::system::NetworkSettings + std::array<std::array<u8, 0x400>, 32> network_settings_1B0; + + // nn::settings::system::BluetoothDevicesSettings + std::array<u8, 0x4> bluetooth_device_settings_count; + bool bluetooth_enable_flag; + std::array<u8, 0x3> pad_08065; + bool bluetooth_afh_enable_flag; + std::array<u8, 0x3> pad_08069; + bool bluetooth_boost_enable_flag; + std::array<u8, 0x3> pad_0806D; + std::array<std::array<u8, 0x200>, 10> bluetooth_device_settings_first_10; + + s32 ldn_channel; + + std::array<u8, 0x3C> reserved_09474; + + // nn::util::Uuid MiiAuthorId + std::array<u8, 0x10> mii_author_id; + + std::array<u8, 0x30> reserved_094C0; + + // nn::settings::system::NxControllerSettings + u32 nx_controller_settings_count; + + std::array<u8, 0xC> reserved_094F4; + + // nn::settings::system::NxControllerSettings, + // nn::settings::system::NxControllerLegacySettings on 13.0.0+ + std::array<std::array<u8, 0x40>, 10> nx_controller_legacy_settings; + + std::array<u8, 0x170> reserved_09780; + + bool external_rtc_reset_flag; + std::array<u8, 0x3> pad_098F1; + + std::array<u8, 0x3C> reserved_098F4; + + s32 push_notification_activity_mode_on_sleep; + + std::array<u8, 0x3C> reserved_09934; + + // nn::settings::system::ErrorReportSharePermission + ErrorReportSharePermission error_report_share_permssion; + + std::array<u8, 0x3C> reserved_09974; + + // nn::settings::KeyboardLayout + std::array<u8, 0x4> keyboard_layout; + + std::array<u8, 0x3C> reserved_099B4; + + bool web_inspector_flag; + std::array<u8, 0x3> pad_099F1; + + // nn::settings::system::AllowedSslHost + u32 allowed_ssl_host_count; + + bool memory_usage_rate_flag; + std::array<u8, 0x3> pad_099F9; + + std::array<u8, 0x34> reserved_099FC; + + // nn::settings::system::HostFsMountPoint + std::array<u8, 0x100> host_fs_mount_point; + + // nn::settings::system::AllowedSslHost + std::array<std::array<u8, 0x100>, 8> allowed_ssl_hosts; + + std::array<u8, 0x6C0> reserved_0A330; + + // nn::settings::system::BlePairingSettings + u32 ble_pairing_settings_count; + std::array<u8, 0xC> reserved_0A9F4; + std::array<std::array<u8, 0x80>, 10> ble_pairing_settings; + + // nn::settings::system::AccountOnlineStorageSettings + u32 account_online_storage_settings_count; + std::array<u8, 0xC> reserved_0AF04; + std::array<std::array<u8, 0x40>, 8> account_online_storage_settings; + + bool pctl_ready_flag; + std::array<u8, 0x3> pad_0B111; + + std::array<u8, 0x3C> reserved_0B114; + + // nn::settings::system::ThemeId + std::array<u8, 0x80> theme_id_type0; + std::array<u8, 0x80> theme_id_type1; + + std::array<u8, 0x100> reserved_0B250; + + // nn::settings::ChineseTraditionalInputMethod + ChineseTraditionalInputMethod chinese_traditional_input_method; + + std::array<u8, 0x3C> reserved_0B354; + + bool zoom_flag; + std::array<u8, 0x3> pad_0B391; + + std::array<u8, 0x3C> reserved_0B394; + + // nn::settings::system::ButtonConfigRegisteredSettings + u32 button_config_registered_settings_count; + std::array<u8, 0xC> reserved_0B3D4; + + // nn::settings::system::ButtonConfigSettings + u32 button_config_settings_count; + std::array<u8, 0x4> reserved_0B3E4; + std::array<std::array<u8, 0x5A8>, 5> button_config_settings; + std::array<u8, 0x13B0> reserved_0D030; + u32 button_config_settings_embedded_count; + std::array<u8, 0x4> reserved_0E3E4; + std::array<std::array<u8, 0x5A8>, 5> button_config_settings_embedded; + std::array<u8, 0x13B0> reserved_10030; + u32 button_config_settings_left_count; + std::array<u8, 0x4> reserved_113E4; + std::array<std::array<u8, 0x5A8>, 5> button_config_settings_left; + std::array<u8, 0x13B0> reserved_13030; + u32 button_config_settings_right_count; + std::array<u8, 0x4> reserved_143E4; + std::array<std::array<u8, 0x5A8>, 5> button_config_settings_right; + std::array<u8, 0x73B0> reserved_16030; + // nn::settings::system::ButtonConfigRegisteredSettings + std::array<u8, 0x5C8> button_config_registered_settings_embedded; + std::array<std::array<u8, 0x5C8>, 10> button_config_registered_settings; + + std::array<u8, 0x7FF8> reserved_21378; + + // nn::settings::system::ConsoleSixAxisSensorAccelerationBias + std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias + std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias; + // nn::settings::system::ConsoleSixAxisSensorAccelerationGain + std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain + std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain; + // nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias + std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias; + // nn::settings::system::ConsoleSixAxisSensorAngularAcceleration + std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration; + + std::array<u8, 0x70> reserved_29400; + + bool lock_screen_flag; + std::array<u8, 0x3> pad_29471; + + std::array<u8, 0x4> reserved_249274; + + ColorSet color_set_id; + + QuestFlag quest_flag; + + // nn::settings::system::RegionCode + RegionCode region_code; + + // Different to nn::settings::system::InitialLaunchSettings? + InitialLaunchSettingsPacked initial_launch_settings_packed; + + bool battery_percentage_flag; + std::array<u8, 0x3> pad_294A1; + + // BitFlagSet<32, nn::settings::system::AppletLaunchFlag> + u32 applet_launch_flag; + + // nn::settings::system::ThemeSettings + std::array<u8, 0x8> theme_settings; + // nn::fssystem::ArchiveMacKey + std::array<u8, 0x10> theme_key; + + bool field_testing_flag; + std::array<u8, 0x3> pad_294C1; + + s32 panel_crc_mode; + + std::array<u8, 0x28> reserved_294C8; + + // nn::settings::system::BacklightSettings + std::array<u8, 0x2C> backlight_settings_mixed_up; + + std::array<u8, 0x64> reserved_2951C; + + // nn::time::SystemClockContext + Service::Time::Clock::SystemClockContext user_system_clock_context; + Service::Time::Clock::SystemClockContext network_system_clock_context; + bool user_system_clock_automatic_correction_enabled; + std::array<u8, 0x3> pad_295C1; + std::array<u8, 0x4> reserved_295C4; + // nn::time::SteadyClockTimePoint + Service::Time::Clock::SteadyClockTimePoint + user_system_clock_automatic_correction_updated_time_point; + + std::array<u8, 0x10> reserved_295E0; + + // nn::settings::system::AccountSettings + AccountSettings account_settings; + + std::array<u8, 0xFC> reserved_295F4; + + // nn::settings::system::AudioVolume + std::array<u8, 0x8> audio_volume_type0; + std::array<u8, 0x8> audio_volume_type1; + // nn::settings::system::AudioOutputMode + s32 audio_output_mode_type0; + s32 audio_output_mode_type1; + s32 audio_output_mode_type2; + bool force_mute_on_headphone_removed; + std::array<u8, 0x3> pad_2970D; + s32 headphone_volume_warning_count; + bool heaphone_volume_update_flag; + std::array<u8, 0x3> pad_29715; + // nn::settings::system::AudioVolume + std::array<u8, 0x8> audio_volume_type2; + // nn::settings::system::AudioOutputMode + s32 audio_output_mode_type3; + s32 audio_output_mode_type4; + bool hearing_protection_safeguard_flag; + std::array<u8, 0x3> pad_29729; + std::array<u8, 0x4> reserved_2972C; + s64 hearing_protection_safeguard_remaining_time; + std::array<u8, 0x38> reserved_29738; + + bool console_information_upload_flag; + std::array<u8, 0x3> pad_29771; + + std::array<u8, 0x3C> reserved_29774; + + bool automatic_application_download_flag; + std::array<u8, 0x3> pad_297B1; + + std::array<u8, 0x4> reserved_297B4; + + // nn::settings::system::NotificationSettings + NotificationSettings notification_settings; + + std::array<u8, 0x60> reserved_297D0; + + // nn::settings::system::AccountNotificationSettings + u32 account_notification_settings_count; + std::array<u8, 0xC> reserved_29834; + std::array<AccountNotificationSettings, 8> account_notification_settings; + + std::array<u8, 0x140> reserved_29900; + + f32 vibration_master_volume; + + bool usb_full_key_enable_flag; + std::array<u8, 0x3> pad_29A45; + + // nn::settings::system::AnalogStickUserCalibration + std::array<u8, 0x10> analog_stick_user_calibration_left; + std::array<u8, 0x10> analog_stick_user_calibration_right; + + // nn::settings::system::TouchScreenMode + s32 touch_screen_mode; + + std::array<u8, 0x14> reserved_29A6C; + + // nn::settings::system::TvSettings + TvSettings tv_settings; + + // nn::settings::system::Edid + std::array<u8, 0x100> edid; + + std::array<u8, 0x2E0> reserved_29BA0; + + // nn::settings::system::DataDeletionSettings + std::array<u8, 0x8> data_deletion_settings; + + std::array<u8, 0x38> reserved_29E88; + + // nn::ncm::ProgramId + std::array<u8, 0x8> initial_system_applet_program_id; + std::array<u8, 0x8> overlay_disp_program_id; + + std::array<u8, 0x4> reserved_29ED0; + + bool requires_run_repair_time_reviser; + + std::array<u8, 0x6B> reserved_29ED5; + + // nn::time::LocationName + Service::Time::TimeZone::LocationName device_time_zone_location_name; + std::array<u8, 0x4> reserved_29F64; + // nn::time::SteadyClockTimePoint + Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time; + + std::array<u8, 0xC0> reserved_29F80; + + // nn::settings::system::PrimaryAlbumStorage + PrimaryAlbumStorage primary_album_storage; + + std::array<u8, 0x3C> reserved_2A044; + + bool usb_30_enable_flag; + std::array<u8, 0x3> pad_2A081; + bool usb_30_host_enable_flag; + std::array<u8, 0x3> pad_2A085; + bool usb_30_device_enable_flag; + std::array<u8, 0x3> pad_2A089; + + std::array<u8, 0x34> reserved_2A08C; + + bool nfc_enable_flag; + std::array<u8, 0x3> pad_2A0C1; + + std::array<u8, 0x3C> reserved_2A0C4; + + // nn::settings::system::SleepSettings + SleepSettings sleep_settings; + + std::array<u8, 0x34> reserved_2A10C; + + // nn::settings::system::EulaVersion + u32 eula_version_count; + std::array<u8, 0xC> reserved_2A144; + std::array<EulaVersion, 32> eula_versions; + + std::array<u8, 0x200> reserved_2A750; + + // nn::settings::system::DeviceNickName + std::array<u8, 0x80> device_nick_name; + + std::array<u8, 0x80> reserved_2A9D0; + + bool auto_update_enable_flag; + std::array<u8, 0x3> pad_2AA51; + + std::array<u8, 0x4C> reserved_2AA54; + + // nn::settings::system::BluetoothDevicesSettings + std::array<std::array<u8, 0x200>, 14> bluetooth_device_settings_last_14; + + std::array<u8, 0x2000> reserved_2C6A0; + + // nn::settings::system::NxControllerSettings + std::array<std::array<u8, 0x800>, 10> nx_controller_settings_data_from_offset_30; +}; + +static_assert(offsetof(SystemSettings, language_code) == 0x10); +static_assert(offsetof(SystemSettings, network_setting_count) == 0x50); +static_assert(offsetof(SystemSettings, network_settings_1B0) == 0x60); +static_assert(offsetof(SystemSettings, bluetooth_device_settings_count) == 0x8060); +static_assert(offsetof(SystemSettings, bluetooth_enable_flag) == 0x8064); +static_assert(offsetof(SystemSettings, bluetooth_device_settings_first_10) == 0x8070); +static_assert(offsetof(SystemSettings, ldn_channel) == 0x9470); +static_assert(offsetof(SystemSettings, mii_author_id) == 0x94B0); +static_assert(offsetof(SystemSettings, nx_controller_settings_count) == 0x94F0); +static_assert(offsetof(SystemSettings, nx_controller_legacy_settings) == 0x9500); +static_assert(offsetof(SystemSettings, external_rtc_reset_flag) == 0x98F0); +static_assert(offsetof(SystemSettings, push_notification_activity_mode_on_sleep) == 0x9930); +static_assert(offsetof(SystemSettings, allowed_ssl_host_count) == 0x99F4); +static_assert(offsetof(SystemSettings, host_fs_mount_point) == 0x9A30); +static_assert(offsetof(SystemSettings, allowed_ssl_hosts) == 0x9B30); +static_assert(offsetof(SystemSettings, ble_pairing_settings_count) == 0xA9F0); +static_assert(offsetof(SystemSettings, ble_pairing_settings) == 0xAA00); +static_assert(offsetof(SystemSettings, account_online_storage_settings_count) == 0xAF00); +static_assert(offsetof(SystemSettings, account_online_storage_settings) == 0xAF10); +static_assert(offsetof(SystemSettings, pctl_ready_flag) == 0xB110); +static_assert(offsetof(SystemSettings, theme_id_type0) == 0xB150); +static_assert(offsetof(SystemSettings, chinese_traditional_input_method) == 0xB350); +static_assert(offsetof(SystemSettings, button_config_registered_settings_count) == 0xB3D0); +static_assert(offsetof(SystemSettings, button_config_settings_count) == 0xB3E0); +static_assert(offsetof(SystemSettings, button_config_settings) == 0xB3E8); +static_assert(offsetof(SystemSettings, button_config_registered_settings_embedded) == 0x1D3E0); +static_assert(offsetof(SystemSettings, console_six_axis_sensor_acceleration_bias) == 0x29370); +static_assert(offsetof(SystemSettings, lock_screen_flag) == 0x29470); +static_assert(offsetof(SystemSettings, battery_percentage_flag) == 0x294A0); +static_assert(offsetof(SystemSettings, field_testing_flag) == 0x294C0); +static_assert(offsetof(SystemSettings, backlight_settings_mixed_up) == 0x294F0); +static_assert(offsetof(SystemSettings, user_system_clock_context) == 0x29580); +static_assert(offsetof(SystemSettings, network_system_clock_context) == 0x295A0); +static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_enabled) == 0x295C0); +static_assert(offsetof(SystemSettings, user_system_clock_automatic_correction_updated_time_point) == + 0x295C8); +static_assert(offsetof(SystemSettings, account_settings) == 0x295F0); +static_assert(offsetof(SystemSettings, audio_volume_type0) == 0x296F0); +static_assert(offsetof(SystemSettings, hearing_protection_safeguard_remaining_time) == 0x29730); +static_assert(offsetof(SystemSettings, automatic_application_download_flag) == 0x297B0); +static_assert(offsetof(SystemSettings, notification_settings) == 0x297B8); +static_assert(offsetof(SystemSettings, account_notification_settings) == 0x29840); +static_assert(offsetof(SystemSettings, vibration_master_volume) == 0x29A40); +static_assert(offsetof(SystemSettings, analog_stick_user_calibration_left) == 0x29A48); +static_assert(offsetof(SystemSettings, touch_screen_mode) == 0x29A68); +static_assert(offsetof(SystemSettings, edid) == 0x29AA0); +static_assert(offsetof(SystemSettings, data_deletion_settings) == 0x29E80); +static_assert(offsetof(SystemSettings, requires_run_repair_time_reviser) == 0x29ED4); +static_assert(offsetof(SystemSettings, device_time_zone_location_name) == 0x29F40); +static_assert(offsetof(SystemSettings, nfc_enable_flag) == 0x2A0C0); +static_assert(offsetof(SystemSettings, eula_version_count) == 0x2A140); +static_assert(offsetof(SystemSettings, device_nick_name) == 0x2A950); +static_assert(offsetof(SystemSettings, bluetooth_device_settings_last_14) == 0x2AAA0); +static_assert(offsetof(SystemSettings, nx_controller_settings_data_from_offset_30) == 0x2E6A0); + +static_assert(sizeof(SystemSettings) == 0x336A0, "SystemSettings has the wrong size!"); + +SystemSettings DefaultSystemSettings(); + +} // namespace Service::Set 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/hle/service/vi/display/vi_display.cpp b/src/core/hle/service/vi/display/vi_display.cpp index d30f49877..71ce9be50 100644 --- a/src/core/hle/service/vi/display/vi_display.cpp +++ b/src/core/hle/service/vi/display/vi_display.cpp @@ -51,11 +51,24 @@ Display::~Display() { } Layer& Display::GetLayer(std::size_t index) { - return *layers.at(index); + size_t i = 0; + for (auto& layer : layers) { + if (!layer->IsOpen()) { + continue; + } + + if (i == index) { + return *layer; + } + + i++; + } + + UNREACHABLE(); } -const Layer& Display::GetLayer(std::size_t index) const { - return *layers.at(index); +size_t Display::GetNumLayers() const { + return std::ranges::count_if(layers, [](auto& l) { return l->IsOpen(); }); } Result Display::GetVSyncEvent(Kernel::KReadableEvent** out_vsync_event) { @@ -92,7 +105,11 @@ void Display::CreateLayer(u64 layer_id, u32 binder_id, hos_binder_driver_server.RegisterProducer(std::move(producer)); } -void Display::CloseLayer(u64 layer_id) { +void Display::DestroyLayer(u64 layer_id) { + if (auto* layer = this->FindLayer(layer_id); layer != nullptr) { + layer->GetConsumer().Abandon(); + } + std::erase_if(layers, [layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; }); } diff --git a/src/core/hle/service/vi/display/vi_display.h b/src/core/hle/service/vi/display/vi_display.h index 101cbce20..1d9360b96 100644 --- a/src/core/hle/service/vi/display/vi_display.h +++ b/src/core/hle/service/vi/display/vi_display.h @@ -66,18 +66,13 @@ public: /// Whether or not this display has any layers added to it. bool HasLayers() const { - return !layers.empty(); + return GetNumLayers() > 0; } /// Gets a layer for this display based off an index. Layer& GetLayer(std::size_t index); - /// Gets a layer for this display based off an index. - const Layer& GetLayer(std::size_t index) const; - - std::size_t GetNumLayers() const { - return layers.size(); - } + std::size_t GetNumLayers() const; /** * Gets the internal vsync event. @@ -100,11 +95,11 @@ public: /// void CreateLayer(u64 layer_id, u32 binder_id, Service::Nvidia::NvCore::Container& core); - /// Closes and removes a layer from this display with the given ID. + /// Removes a layer from this display with the given ID. /// - /// @param layer_id The ID assigned to the layer to close. + /// @param layer_id The ID assigned to the layer to destroy. /// - void CloseLayer(u64 layer_id); + void DestroyLayer(u64 layer_id); /// Resets the display for a new connection. void Reset() { diff --git a/src/core/hle/service/vi/layer/vi_layer.cpp b/src/core/hle/service/vi/layer/vi_layer.cpp index 9ae2e0e44..04e52a23b 100644 --- a/src/core/hle/service/vi/layer/vi_layer.cpp +++ b/src/core/hle/service/vi/layer/vi_layer.cpp @@ -8,8 +8,8 @@ namespace Service::VI { Layer::Layer(u64 layer_id_, u32 binder_id_, android::BufferQueueCore& core_, android::BufferQueueProducer& binder_, std::shared_ptr<android::BufferItemConsumer>&& consumer_) - : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, consumer{std::move( - consumer_)} {} + : layer_id{layer_id_}, binder_id{binder_id_}, core{core_}, binder{binder_}, + consumer{std::move(consumer_)}, open{false} {} Layer::~Layer() = default; diff --git a/src/core/hle/service/vi/layer/vi_layer.h b/src/core/hle/service/vi/layer/vi_layer.h index 8cf1b5275..295005e23 100644 --- a/src/core/hle/service/vi/layer/vi_layer.h +++ b/src/core/hle/service/vi/layer/vi_layer.h @@ -71,12 +71,25 @@ public: return core; } + bool IsOpen() const { + return open; + } + + void Close() { + open = false; + } + + void Open() { + open = true; + } + private: const u64 layer_id; const u32 binder_id; android::BufferQueueCore& core; android::BufferQueueProducer& binder; std::shared_ptr<android::BufferItemConsumer> consumer; + bool open; }; } // namespace Service::VI diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index b1bfb9898..9ab8788e3 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -719,6 +719,8 @@ private: return; } + nv_flinger.OpenLayer(layer_id); + android::OutputParcel parcel; parcel.WriteInterface(NativeWindow{*buffer_queue_id}); @@ -783,6 +785,7 @@ private: const u64 layer_id = rp.Pop<u64>(); LOG_WARNING(Service_VI, "(STUBBED) called. layer_id=0x{:016X}", layer_id); + nv_flinger.DestroyLayer(layer_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); 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/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/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/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 0d5a1709f..d7941f6a4 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -2080,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)) { @@ -2091,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); }); } @@ -2106,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)); @@ -2117,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); } } |