diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index d93cc1cfc9..623597152f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -36,7 +36,7 @@ public: u64 MemoryRead64(u32 vaddr) override; std::optional MemoryReadCode(u32 vaddr) override; void InstructionSynchronizationBarrierRaised() override { - last_code_addr = 0; //reset back, force refetch + last_code_addr = u64(-1); //reset back, force refetch } void MemoryWrite8(u32 vaddr, u8 value) override; void MemoryWrite16(u32 vaddr, u16 value) override; @@ -54,7 +54,7 @@ public: void ReturnException(u32 pc, Dynarmic::HaltReason hr); // Dynarmic::CodePage cached_code_page; - u64 last_code_addr = 0; + u64 last_code_addr = u64(-1); ArmDynarmic32& m_parent; Core::Memory::Memory& m_memory; Kernel::KProcess* m_process{}; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index db8f4424eb..63cc33d9c8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -45,7 +45,6 @@ Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) { std::optional DynarmicCallbacks64::MemoryReadCode(u64 vaddr) { if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32))) return std::nullopt; -// return m_memory.Read32(vaddr); auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK; if (last_code_addr != aligned_vaddr) { m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page)); @@ -103,6 +102,7 @@ bool DynarmicCallbacks64::MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vect } void DynarmicCallbacks64::InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) { + last_code_addr = u64(-1); //invalidate cached page switch (op) { case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: { static constexpr u64 ICACHE_LINE_SIZE = 64; @@ -128,7 +128,7 @@ void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception excep case Dynarmic::A64::Exception::SendEvent: case Dynarmic::A64::Exception::SendEventLocal: case Dynarmic::A64::Exception::Yield: - LOG_TRACE(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})", static_cast(exception), pc, m_memory.Read32(pc)); + LOG_TRACE(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, cached = {:08X})", std::size_t(exception), pc, m_memory.Read32(pc), MemoryReadCode(pc).value_or(0)); return; case Dynarmic::A64::Exception::NoExecuteFault: LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc); diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 9eff17c5fe..6d0760986f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -43,7 +43,7 @@ public: Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override; std::optional MemoryReadCode(u64 vaddr) override; void InstructionSynchronizationBarrierRaised() override { - last_code_addr = 0; //reset back, force refetch + last_code_addr = u64(-1); //reset back, force refetch } void MemoryWrite8(u64 vaddr, u8 value) override; void MemoryWrite16(u64 vaddr, u16 value) override; @@ -65,7 +65,7 @@ public: void ReturnException(u64 pc, Dynarmic::HaltReason hr); Dynarmic::CodePage cached_code_page; - u64 last_code_addr = 0; + u64 last_code_addr = u64(-1); ArmDynarmic64& m_parent; Core::Memory::Memory& m_memory; u64 m_tpidrro_el0{}; diff --git a/src/core/arm/symbols.cpp b/src/core/arm/symbols.cpp index 0259c7ea27..4e270c319e 100644 --- a/src/core/arm/symbols.cpp +++ b/src/core/arm/symbols.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -13,117 +16,111 @@ using namespace Common::ELF; namespace Core { namespace Symbols { -template -static Symbols GetSymbols(ByteReader ReadBytes) { - const auto Read8{[&](u64 index) { +struct ModuleHeaderLocation { + u32 version; + u32 header_offset; + u32 version_offset; +}; +static_assert(sizeof(ModuleHeaderLocation) == 0x0C); +struct ModuleHeader { + u32 signature; + u32 dynamic_offset; + u32 bss_start_offset; + u32 bss_end_offset; + u32 exception_info_start_offset; + u32 exception_info_end_offset; + u32 module_offset; + u32 relro_start_offset; + u32 full_relro_end_offset; + u32 nx_debug_link_start_offset; + u32 nx_debug_link_end_offset; + u32 note_gnu_build_id_start_offset; + u32 note_gnu_build_id_end_offset; +}; +static_assert(sizeof(ModuleHeader) == 0x34); + +struct Mod32 { + using Sym = Elf32_Sym; + using Dyn = Elf32_Dyn; +}; +struct Mod64 { + using Sym = Elf64_Sym; + using Dyn = Elf64_Dyn; +}; + +template +static Symbols GetSymbols(F&& ReadBytes) { + const auto Read8 = [&](u64 index) { u8 ret; ReadBytes(&ret, index, sizeof(u8)); return ret; - }}; - - const auto Read32{[&](u64 index) { - u32 ret; - ReadBytes(&ret, index, sizeof(u32)); - return ret; - }}; - - const auto ReadWord{[&](u64 index) { - Word ret; - ReadBytes(&ret, index, sizeof(Word)); - return ret; - }}; - - const u32 mod_offset = Read32(4); - - if (Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { + }; + ModuleHeaderLocation loc{}; + ReadBytes(&loc, 0, sizeof(ModuleHeaderLocation)); + ModuleHeader hdr; + ReadBytes(&hdr, loc.header_offset, sizeof(ModuleHeader)); + if (hdr.signature != Common::MakeMagic('M', 'O', 'D', '0')) { return {}; } - VAddr string_table_offset{}; - VAddr symbol_table_offset{}; - u64 symbol_entry_size{}; - - const auto dynamic_offset = Read32(mod_offset + 0x4) + mod_offset; - - VAddr dynamic_index = dynamic_offset; + VAddr strtab_offs{}; + VAddr symtab_offs{}; + u64 syment_size = sizeof(typename M::Sym); + VAddr dynamic_offset = loc.header_offset + hdr.dynamic_offset; while (true) { - const Word tag = ReadWord(dynamic_index); - const Word value = ReadWord(dynamic_index + sizeof(Word)); - dynamic_index += 2 * sizeof(Word); - - if (tag == ElfDtNull) { + typename M::Dyn dyn; + ReadBytes(&dyn, dynamic_offset, sizeof(typename M::Dyn)); + dynamic_offset += sizeof(typename M::Dyn); + if (dyn.d_tag == ElfDtNull) { break; } - - if (tag == ElfDtStrtab) { - string_table_offset = value; - } else if (tag == ElfDtSymtab) { - symbol_table_offset = value; - } else if (tag == ElfDtSyment) { - symbol_entry_size = value; + if (dyn.d_tag == ElfDtStrtab) { + strtab_offs = dyn.d_un.d_ptr; + } else if (dyn.d_tag == ElfDtSymtab) { + symtab_offs = dyn.d_un.d_ptr; + } else if (dyn.d_tag == ElfDtSyment) { + syment_size = dyn.d_un.d_val; } } - - if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) { - return {}; - } - - Symbols out; - - VAddr symbol_index = symbol_table_offset; - while (symbol_index < string_table_offset) { - ELFSymbol symbol{}; - ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol)); - - VAddr string_offset = string_table_offset + symbol.st_name; - std::string name; - for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { - name += static_cast(c); + if (strtab_offs > 0 && symtab_offs > 0) { + Symbols out; + VAddr symbol_index = symtab_offs; + while (symbol_index < strtab_offs) { + typename M::Sym symbol{}; + ReadBytes(&symbol, symbol_index, sizeof(typename M::Sym)); + VAddr offs = strtab_offs + symbol.st_name; + std::string name{}; + for (u8 c = Read8(offs); c != 0; c = Read8(++offs)) + name += char(c); + symbol_index += syment_size; + out[name] = std::make_pair(symbol.st_value, symbol.st_size); } - - symbol_index += symbol_entry_size; - out[name] = std::make_pair(symbol.st_value, symbol.st_size); + return out; } - - return out; + return {}; } Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) { - const auto ReadBytes{ - [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }}; - - if (is_64) { - return GetSymbols(ReadBytes); - } else { - return GetSymbols(ReadBytes); - } + const auto f = [base, &memory](void* ptr, size_t offset, size_t size) { + memory.ReadBlock(base + offset, ptr, size); + }; + return is_64 ? GetSymbols(f) : GetSymbols(f); } Symbols GetSymbols(std::span data, bool is_64) { - const auto ReadBytes{[&](void* ptr, size_t offset, size_t size) { + const auto f = [data](void* ptr, size_t offset, size_t size) { std::memcpy(ptr, data.data() + offset, size); - }}; - - if (is_64) { - return GetSymbols(ReadBytes); - } else { - return GetSymbols(ReadBytes); - } + }; + return is_64 ? GetSymbols(f) : GetSymbols(f); } std::optional GetSymbolName(const Symbols& symbols, VAddr addr) { - const auto iter = std::find_if(symbols.cbegin(), symbols.cend(), [addr](const auto& pair) { - const auto& [name, sym_info] = pair; - const auto& [start_address, size] = sym_info; - const auto end_address = start_address + size; - return addr >= start_address && addr < end_address; + const auto it = std::find_if(symbols.cbegin(), symbols.cend(), [addr](const auto& e) { + auto const [start, size] = e.second; + auto const end = start + size; + return addr >= start && addr < end; }); - - if (iter == symbols.cend()) { - return std::nullopt; - } - - return iter->first; + return it != symbols.cend() ? std::optional{it->first} : std::nullopt; } } // namespace Symbols diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp index 8622ab058f..d89f147a75 100644 --- a/src/core/hle/service/caps/caps_su.cpp +++ b/src/core/hle/service/caps/caps_su.cpp @@ -33,8 +33,7 @@ IScreenShotApplicationService::IScreenShotApplicationService( IScreenShotApplicationService::~IScreenShotApplicationService() = default; -Result IScreenShotApplicationService::SetShimLibraryVersion(ShimLibraryVersion library_version, - ClientAppletResourceUserId aruid) { +Result IScreenShotApplicationService::SetShimLibraryVersion(ShimLibraryVersion library_version, ClientAppletResourceUserId aruid) { LOG_WARNING(Service_Capture, "(STUBBED) called. library_version={}, applet_resource_user_id={}", library_version, aruid.pid); R_SUCCEED(); diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index 4941a71a01..1179e8b61d 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp @@ -1,6 +1,10 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/logging.h" #include "core/arm/debug.h" #include "core/arm/symbols.h" #include "core/core.h" @@ -111,10 +115,7 @@ public: const VAddr input_ptr{context.AddHeap(in_data.data(), in_data.size())}; const VAddr output_ptr{context.AddHeap(out_data.data(), out_data.size())}; - const u64 wrapper_value{context.CallFunction(callbacks.Control, ret_ptr, configuration_ptr, - command, input_ptr, in_data.size(), output_ptr, - out_data.size())}; - + const u64 wrapper_value = context.CallFunction(callbacks.Control, ret_ptr, configuration_ptr, command, input_ptr, in_data.size(), output_ptr, out_data.size()); *out_return_value = context.GetHeap(ret_ptr); context.GetHeap(output_ptr, out_data.data(), out_data.size()); @@ -126,9 +127,7 @@ public: R_THROW(ResultUnknown); } - Result LoadPlugin(u64 tmem_size, InCopyHandle tmem, - InBuffer nrr, - InBuffer nro) { + Result LoadPlugin(u64 tmem_size, InCopyHandle tmem, InBuffer nrr, InBuffer nro) { if (!tmem) { LOG_ERROR(Service_JIT, "Invalid transfer memory handle!"); R_THROW(ResultUnknown); @@ -139,9 +138,10 @@ public: configuration.transfer_memory.size = tmem_size; // Gather up all the callbacks from the loaded plugin - auto symbols{Core::Symbols::GetSymbols(nro, true)}; - const auto GetSymbol{[&](const std::string& name) { return symbols[name].first; }}; - + auto symbols = Core::Symbols::GetSymbols(nro, true); + const auto GetSymbol = [&](const std::string& name) { + return symbols[name].first; + }; callbacks.rtld_fini = GetSymbol("_fini"); callbacks.rtld_init = GetSymbol("_init"); callbacks.Control = GetSymbol("nnjitpluginControl"); @@ -153,8 +153,7 @@ public: callbacks.OnPrepared = GetSymbol("nnjitpluginOnPrepared"); callbacks.Keeper = GetSymbol("nnjitpluginKeeper"); - if (callbacks.GetVersion == 0 || callbacks.Configure == 0 || callbacks.GenerateCode == 0 || - callbacks.OnPrepared == 0) { + if (callbacks.GetVersion == 0 || callbacks.Configure == 0 || callbacks.GenerateCode == 0 || callbacks.OnPrepared == 0 || callbacks.Control == 0) { LOG_ERROR(Service_JIT, "plugin does not implement all necessary functionality"); R_THROW(ResultUnknown); } @@ -164,12 +163,9 @@ public: R_THROW(ResultUnknown); } - context.MapProcessMemory(configuration.sys_ro_memory.offset, - configuration.sys_ro_memory.size); - context.MapProcessMemory(configuration.sys_rx_memory.offset, - configuration.sys_rx_memory.size); - context.MapProcessMemory(configuration.transfer_memory.offset, - configuration.transfer_memory.size); + context.MapProcessMemory(configuration.sys_ro_memory.offset, configuration.sys_ro_memory.size); + context.MapProcessMemory(configuration.sys_rx_memory.offset, configuration.sys_rx_memory.size); + context.MapProcessMemory(configuration.transfer_memory.offset, configuration.transfer_memory.size); // Run ELF constructors, if needed if (callbacks.rtld_init != 0) { @@ -179,7 +175,7 @@ public: // Function prototype: // u64 GetVersion(); const auto version{context.CallFunction(callbacks.GetVersion)}; - if (version != 1) { + if (version > 1) { LOG_ERROR(Service_JIT, "unknown plugin version {}", version); R_THROW(ResultUnknown); } diff --git a/src/core/hle/service/jit/jit_context.cpp b/src/core/hle/service/jit/jit_context.cpp index 522d849e6f..ce51fbd3f5 100644 --- a/src/core/hle/service/jit/jit_context.cpp +++ b/src/core/hle/service/jit/jit_context.cpp @@ -24,15 +24,25 @@ using namespace Common::ELF; namespace Service::JIT { +enum HelperFn { + None, + Stop, + Resolve, + Panic, + Memcpy, + Memmove, + Memset, + // sm64 + PanicForPlugin, + AbortImpl, + UnexpectedImpl, + Count +}; + constexpr std::array SVC0_ARM64 = { 0x01, 0x00, 0x00, 0xd4, // svc #0 0xc0, 0x03, 0x5f, 0xd6, // ret }; - -constexpr std::array HELPER_FUNCTIONS{ - "_stop", "_resolve", "_panic", "memcpy", "memmove", "memset", -}; - constexpr size_t STACK_ALIGN = 16; class JITContextImpl; @@ -42,10 +52,12 @@ using IntervalType = boost::icl::interval_set::interval_type; class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { public: - explicit DynarmicCallbacks64(Core::Memory::Memory& memory_, std::vector& local_memory_, - IntervalSet& mapped_ranges_, JITContextImpl& parent_) - : memory{memory_}, local_memory{local_memory_}, - mapped_ranges{mapped_ranges_}, parent{parent_} {} + explicit DynarmicCallbacks64(Core::Memory::Memory& memory_, std::vector& local_memory_, IntervalSet& mapped_ranges_, JITContextImpl& parent_) + : memory{memory_} + , local_memory{local_memory_} + , mapped_ranges{mapped_ranges_} + , parent{parent_} + {} std::optional MemoryReadCode(VAddr vaddr) override { static_assert(Core::Memory::YUZU_PAGESIZE == Dynarmic::CODE_PAGE_SIZE); @@ -57,7 +69,7 @@ public: return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)]; } void InstructionSynchronizationBarrierRaised() override { - last_code_addr = 0; //reset back, force refetch + last_code_addr = u64(-1); //reset back, force refetch } u8 MemoryRead8(u64 vaddr) override { return ReadMemory(vaddr); @@ -75,13 +87,10 @@ public: return ReadMemory(vaddr); } std::string MemoryReadCString(u64 vaddr) { - std::string result; + std::string result{}; u8 next; - - while ((next = MemoryRead8(vaddr++)) != 0) { - result += next; - } - + while ((next = MemoryRead8(vaddr++)) != 0) + result += char(next); return result; } @@ -157,32 +166,26 @@ private: std::vector& local_memory; IntervalSet& mapped_ranges; JITContextImpl& parent; - Dynarmic::CodePage cached_code_page; - u64 last_code_addr = 0; + u64 last_code_addr = u64(-1); }; class JITContextImpl { public: explicit JITContextImpl(Core::Memory::Memory& memory_) : memory{memory_} { - callbacks = - std::make_unique(memory, local_memory, mapped_ranges, *this); - user_config.callbacks = callbacks.get(); - jit = std::make_unique(user_config); + callbacks.emplace(memory, local_memory, mapped_ranges, *this); + user_config.callbacks = std::addressof(callbacks.value()); + jit.emplace(user_config); } bool LoadNRO(std::span data) { - local_memory.clear(); - relocbase = local_memory.size(); local_memory.insert(local_memory.end(), data.begin(), data.end()); - if (FixupRelocations()) { InsertHelperFunctions(); InsertStack(); return true; } - return false; } @@ -190,11 +193,9 @@ public: // The loaded NRO file has ELF relocations that must be processed before it can run. // Normally this would be processed by RTLD, but in HLE context, we don't have // the linker available, so we have to do it ourselves. - const VAddr mod_offset{callbacks->MemoryRead32(4)}; - if (callbacks->MemoryRead32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { + if (callbacks->MemoryRead32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) return false; - } // For more info about dynamic entries, see the ELF ABI specification: // https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html @@ -205,40 +206,33 @@ public: while (true) { const auto dyn{callbacks->ReadMemory(dynamic_offset)}; dynamic_offset += sizeof(Elf64_Dyn); - if (!dyn.d_tag) { break; - } - if (dyn.d_tag == ElfDtRela) { + } else if (dyn.d_tag == ElfDtRela) { rela_dyn = dyn.d_un.d_ptr; - } - if (dyn.d_tag == ElfDtRelasz) { + } else if (dyn.d_tag == ElfDtRelasz) { num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela); - } - if (dyn.d_tag == ElfDtRelr) { + } else if (dyn.d_tag == ElfDtRelr) { relr_dyn = dyn.d_un.d_ptr; - } - if (dyn.d_tag == ElfDtRelrsz) { + } else if (dyn.d_tag == ElfDtRelrsz) { num_relr = dyn.d_un.d_val / sizeof(Elf64_Relr); } } for (size_t i = 0; i < num_rela; i++) { const auto rela{callbacks->ReadMemory(rela_dyn + i * sizeof(Elf64_Rela))}; - if (Elf64RelType(rela.r_info) != ElfAArch64Relative) { - continue; + if (Elf64RelType(rela.r_info) == ElfAArch64Relative) { + const VAddr contents{callbacks->MemoryRead64(rela.r_offset)}; + callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend); } - const VAddr contents{callbacks->MemoryRead64(rela.r_offset)}; - callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend); } VAddr relr_where = 0; for (size_t i = 0; i < num_relr; i++) { - const auto relr{callbacks->ReadMemory(relr_dyn + i * sizeof(Elf64_Relr))}; - const auto incr{[&](VAddr where) { + const auto relr = callbacks->ReadMemory(relr_dyn + i * sizeof(Elf64_Relr)); + const auto incr = [&](VAddr where) { callbacks->MemoryWrite64(where, callbacks->MemoryRead64(where) + relocbase); - }}; - + }; if ((relr & 1) == 0) { // where pointer relr_where = relocbase + relr; @@ -254,13 +248,12 @@ public: relr_where += 63 * sizeof(Elf64_Addr); } } - return true; } void InsertHelperFunctions() { - for (const auto& name : HELPER_FUNCTIONS) { - helpers[name] = local_memory.size(); + for (size_t i = 0; i < size_t(HelperFn::Count); ++i) { + helpers[i] = local_memory.size(); local_memory.insert(local_memory.end(), SVC0_ARM64.begin(), SVC0_ARM64.end()); } } @@ -268,9 +261,8 @@ public: void InsertStack() { // Allocate enough space to avoid any reasonable risk of // overflowing the stack during plugin execution - const u64 pad_amount{Common::AlignUp(local_memory.size(), STACK_ALIGN) - - local_memory.size()}; - local_memory.insert(local_memory.end(), 0x10000 + pad_amount, 0); + const u64 pad_amount = Common::AlignUp(local_memory.size(), STACK_ALIGN) - local_memory.size(); + local_memory.insert(local_memory.end(), (4096 * 32) + pad_amount, 0); top_of_stack = local_memory.size(); heap_pointer = top_of_stack; } @@ -297,27 +289,21 @@ public: // // For more info, see the AArch64 ABI PCS: // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst - - for (size_t i = 0; i < 8 && i < argument_stack.size(); i++) { + for (size_t i = 0; i < 8 && i < argument_stack.size(); i++) jit->SetRegister(i, argument_stack[i]); - } - if (argument_stack.size() > 8) { - const VAddr new_sp = Common::AlignDown( - top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN); - for (size_t i = 8; i < argument_stack.size(); i++) { + const VAddr new_sp = Common::AlignDown(top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN); + for (size_t i = 8; i < argument_stack.size(); i++) callbacks->MemoryWrite64(new_sp + (i - 8) * sizeof(u64), argument_stack[i]); - } jit->SetSP(new_sp); } - // Reset the call state for the next invocation argument_stack.clear(); heap_pointer = top_of_stack; } u64 CallFunction(VAddr func) { - jit->SetRegister(30, helpers["_stop"]); + jit->SetRegister(30, helpers[size_t(HelperFn::Stop)]); jit->SetSP(top_of_stack); SetupArguments(); @@ -326,21 +312,14 @@ public: return jit->GetRegister(0); } - VAddr GetHelper(const std::string& name) { - return helpers[name]; - } - VAddr AddHeap(const void* data, size_t size) { // Require all heap data types to have the same alignment as the // stack pointer, for compatibility - const size_t num_bytes{Common::AlignUp(size, STACK_ALIGN)}; - + const size_t num_bytes = Common::AlignUp(size, STACK_ALIGN); // Make additional memory space if required if (heap_pointer + num_bytes > local_memory.size()) { - local_memory.insert(local_memory.end(), - (heap_pointer + num_bytes) - local_memory.size(), 0); + local_memory.insert(local_memory.end(), (heap_pointer + num_bytes) - local_memory.size(), 0); } - const VAddr location{heap_pointer}; std::memcpy(local_memory.data() + location, data, size); heap_pointer += num_bytes; @@ -351,13 +330,29 @@ public: std::memcpy(data, local_memory.data() + location, size); } - std::unique_ptr callbacks; + VAddr GetHelper(const std::string& name) { + if (name == "_resolve") return helpers[HelperFn::Resolve]; + else if (name == "_panic") return helpers[HelperFn::Panic]; + else if (name == "_stop") return helpers[HelperFn::Stop]; + else if (name == "memset") return helpers[HelperFn::Memset]; + else if (name == "memcpy") return helpers[HelperFn::Memcpy]; + else if (name == "memmove") return helpers[HelperFn::Memmove]; + else if (name == "PanicForPlugin") return helpers[HelperFn::PanicForPlugin]; + else if (name == "_ZN2nn4diag6detail9AbortImplEPKcS3_S3_i") return helpers[HelperFn::AbortImpl]; + else if (name == "_ZN2nn6detail21UnexpectedDefaultImplEPKcS2_i") return helpers[HelperFn::UnexpectedImpl]; + else { + LOG_CRITICAL(Service_JIT, "unresolved {}", name); + return helpers[HelperFn::Panic]; + } + } + + std::optional callbacks; + std::optional jit; std::vector local_memory; - std::vector argument_stack; + std::vector argument_stack; IntervalSet mapped_ranges; Dynarmic::A64::UserConfig user_config; - std::unique_ptr jit; - std::map> helpers; + std::array helpers; Core::Memory::Memory& memory; VAddr top_of_stack; VAddr heap_pointer; @@ -383,44 +378,41 @@ void DynarmicCallbacks64::CallSVC(u32 swi) { } u64 pc{parent.jit->GetPC() - 4}; - auto& helpers{parent.helpers}; - - if (pc == helpers["memcpy"] || pc == helpers["memmove"]) { + if (pc == parent.helpers[size_t(HelperFn::Memcpy)] || pc == parent.helpers[size_t(HelperFn::Memmove)]) { const VAddr dest{parent.jit->GetRegister(0)}; const VAddr src{parent.jit->GetRegister(1)}; const size_t n{parent.jit->GetRegister(2)}; if (dest < src) { - for (size_t i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) MemoryWrite8(dest + i, MemoryRead8(src + i)); - } } else { - for (size_t i = n; i > 0; i--) { + for (size_t i = n; i > 0; i--) MemoryWrite8(dest + i - 1, MemoryRead8(src + i - 1)); - } } - } else if (pc == helpers["memset"]) { + } else if (pc == parent.helpers[size_t(HelperFn::Memset)]) { const VAddr dest{parent.jit->GetRegister(0)}; const u64 c{parent.jit->GetRegister(1)}; const size_t n{parent.jit->GetRegister(2)}; - - for (size_t i = 0; i < n; i++) { - MemoryWrite8(dest + i, static_cast(c)); - } - } else if (pc == helpers["_resolve"]) { + for (size_t i = 0; i < n; i++) + MemoryWrite8(dest + i, u8(c)); + } else if (pc == parent.helpers[size_t(HelperFn::Resolve)]) { // X0 contains a char* for a symbol to resolve const auto name{MemoryReadCString(parent.jit->GetRegister(0))}; - const auto helper{helpers[name]}; - - if (helper != 0) { - parent.jit->SetRegister(0, helper); - } else { - LOG_WARNING(Service_JIT, "plugin requested unknown function {}", name); - parent.jit->SetRegister(0, helpers["_panic"]); - } - } else if (pc == helpers["_stop"]) { + parent.jit->SetRegister(0, u64(parent.GetHelper(name))); + } else if (pc == parent.helpers[size_t(HelperFn::Stop)]) { parent.jit->HaltExecution(); - } else if (pc == helpers["_panic"]) { + } else if (pc == parent.helpers[size_t(HelperFn::Panic)]) { + LOG_CRITICAL(Service_JIT, "plugin panicked!"); + parent.jit->HaltExecution(); + // SM64 + } else if (pc == parent.helpers[size_t(HelperFn::PanicForPlugin)]) { + LOG_CRITICAL(Service_JIT, "plugin panicked!"); + parent.jit->HaltExecution(); + } else if (pc == parent.helpers[size_t(HelperFn::AbortImpl)]) { + LOG_CRITICAL(Service_JIT, "plugin panicked!"); + parent.jit->HaltExecution(); + } else if (pc == parent.helpers[size_t(HelperFn::UnexpectedImpl)]) { LOG_CRITICAL(Service_JIT, "plugin panicked!"); parent.jit->HaltExecution(); } else { @@ -430,7 +422,8 @@ void DynarmicCallbacks64::CallSVC(u32 swi) { } void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) { - LOG_CRITICAL(Service_JIT, "Illegal operation PC @ {:08x}", pc); + auto const inst = MemoryRead32(pc); + LOG_CRITICAL(Service_JIT, "{} PC @ {:08x}, data = {:08x}", exception, pc, inst); parent.jit->HaltExecution(); }