[nce] common ctx

Signed-off-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2025-08-30 19:40:25 +00:00 committed by crueter
parent f5a2868bbe
commit fc28efb5f5
4 changed files with 40 additions and 114 deletions

View file

@ -13,9 +13,10 @@
#include "core/arm/nce/patcher.h" #include "core/arm/nce/patcher.h"
#include "core/core.h" #include "core/core.h"
#include "core/memory.h" #include "core/memory.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "dynarmic/common/context.h"
#include <signal.h> #include <signal.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
@ -33,20 +34,6 @@ static_assert(offsetof(NativeExecutionParameters, native_context) == TpidrEl0Nat
static_assert(offsetof(NativeExecutionParameters, lock) == TpidrEl0Lock); static_assert(offsetof(NativeExecutionParameters, lock) == TpidrEl0Lock);
static_assert(offsetof(NativeExecutionParameters, magic) == TpidrEl0TlsMagic); static_assert(offsetof(NativeExecutionParameters, magic) == TpidrEl0TlsMagic);
#ifdef __APPLE__
_STRUCT_ARM_NEON_STATE64* GetFloatingPointState(mcontext_t& host_ctx) {
return &(host_ctx.__ns);
}
#else
fpsimd_context* GetFloatingPointState(mcontext_t& host_ctx) {
_aarch64_ctx* header = reinterpret_cast<_aarch64_ctx*>(&host_ctx.__reserved);
while (header->magic != FPSIMD_MAGIC) {
header = reinterpret_cast<_aarch64_ctx*>(reinterpret_cast<char*>(header) + header->size);
}
return reinterpret_cast<fpsimd_context*>(header);
}
#endif
using namespace Common::Literals; using namespace Common::Literals;
constexpr u32 StackSize = 128_KiB; constexpr u32 StackSize = 128_KiB;
@ -59,38 +46,21 @@ void* ArmNce::RestoreGuestContext(void* raw_context) {
auto* fpctx = GetFloatingPointState(host_ctx); auto* fpctx = GetFloatingPointState(host_ctx);
// Restore all guest state except tpidr_el0. // Restore all guest state except tpidr_el0.
#ifdef __APPLE__
// Thread-local parameters will be located in x9. // Thread-local parameters will be located in x9.
auto* tpidr = reinterpret_cast<NativeExecutionParameters*>(host_ctx->__ss.__r[9]); auto* tpidr = reinterpret_cast<NativeExecutionParameters*>(CTX_X(9));
auto* guest_ctx = static_cast<GuestContext*>(tpidr->native_context); auto* guest_ctx = static_cast<GuestContext*>(tpidr->native_context);
// Save host callee-saved registers. // Save host callee-saved registers.
std::memcpy(guest_ctx->host_ctx.host_saved_vregs.data(), &fpctx->__v[8], std::memcpy(guest_ctx->host_ctx.host_saved_vregs.data(), &CTX_Q(8),
sizeof(guest_ctx->host_ctx.host_saved_vregs)); sizeof(guest_ctx->host_ctx.host_saved_vregs));
// Save stack pointer. // Save stack pointer.
guest_ctx->host_ctx.host_sp = host_ctx->__ss.__sp; guest_ctx->host_ctx.host_sp = CTX_SP;
host_ctx->__ss.__pc = guest_ctx->sp; CTX_PC = guest_ctx->sp;
host_ctx->__ss.__sp = guest_ctx->pc; CTX_SP = guest_ctx->pc;
host_ctx->__ss.__pstate = guest_ctx->pstate; CTX_PSTATE = guest_ctx->pstate;
fpctx->__fpcr = guest_ctx->fpcr; CTX_FPCR = guest_ctx->fpcr;
fpctx->__fpsr = guest_ctx->fpsr; CTX_FPSR = guest_ctx->fpsr;
std::memcpy(fpctx->__v, guest_ctx->vector_registers.data(), sizeof(fpctx->__v)); std::memcpy(&CTX_X(0), guest_ctx->cpu_registers.data(), sizeof(guest_ctx->cpu_registers));
#else std::memcpy(&CTX_Q(0), guest_ctx->vector_registers.data(), sizeof(guest_ctx->vector_registers));
// Thread-local parameters will be located in x9.
auto* tpidr = reinterpret_cast<NativeExecutionParameters*>(host_ctx.regs[9]);
auto* guest_ctx = static_cast<GuestContext*>(tpidr->native_context);
// Save host callee-saved registers.
std::memcpy(guest_ctx->host_ctx.host_saved_vregs.data(), &fpctx->vregs[8],
sizeof(guest_ctx->host_ctx.host_saved_vregs));
// Save stack pointer.
guest_ctx->host_ctx.host_sp = host_ctx.sp;
host_ctx.sp = guest_ctx->sp;
host_ctx.pc = guest_ctx->pc;
host_ctx.pstate = guest_ctx->pstate;
fpctx->fpcr = guest_ctx->fpcr;
fpctx->fpsr = guest_ctx->fpsr;
std::memcpy(fpctx->vregs, guest_ctx->vector_registers.data(), sizeof(fpctx->vregs));
#endif
std::memcpy(host_ctx.regs, guest_ctx->cpu_registers.data(), sizeof(host_ctx.regs));
// Return the new thread-local storage pointer. // Return the new thread-local storage pointer.
return tpidr; return tpidr;
} }
@ -103,47 +73,25 @@ void ArmNce::SaveGuestContext(GuestContext* guest_ctx, void* raw_context) {
auto* fpctx = GetFloatingPointState(host_ctx); auto* fpctx = GetFloatingPointState(host_ctx);
// Save all guest registers except tpidr_el0. // Save all guest registers except tpidr_el0.
#ifdef __APPLE__ std::memcpy(guest_ctx->cpu_registers.data(), &CTX_X(0), sizeof(guest_ctx->cpu_registers));
std::memcpy(guest_ctx->cpu_registers.data(), host_ctx->__ss.__r, sizeof(host_ctx->__ss.__r)); std::memcpy(guest_ctx->vector_registers.data(), &CTX_Q(0), sizeof(guest_ctx->vector_registers));
std::memcpy(guest_ctx->vector_registers.data(), fpctx->__v, sizeof(fpctx->__v)); guest_ctx->fpsr = CTX_FPSR;
guest_ctx->fpsr = fpctx->__fpsr; guest_ctx->fpcr = CTX_FPCR;
guest_ctx->fpcr = fpctx->__fpcr; guest_ctx->pc = CTX_PC;
guest_ctx->pstate = static_cast<u32>(host_ctx->__ss.__pstate); guest_ctx->sp = CTX_SP;
guest_ctx->pc = host_ctx->__ss.__pc; guest_ctx->pstate = u32(CTX_PSTATE);
guest_ctx->sp = host_ctx->__ss.__sp;
// Restore stack pointer. // Restore stack pointer.
host_ctx->__ss.__sp = guest_ctx->host_ctx.host_sp; CTX_SP = guest_ctx->host_ctx.host_sp;
// Restore host callee-saved registers.
std::memcpy(&host_ctx->__ss.__r[19], guest_ctx->host_ctx.host_saved_regs.data(),
sizeof(guest_ctx->host_ctx.host_saved_regs));
std::memcpy(&fpctx->__v[8], guest_ctx->host_ctx.host_saved_vregs.data(),
sizeof(guest_ctx->host_ctx.host_saved_vregs));
// Return from the call on exit by setting pc to x30.
host_ctx->__ss.__pc = guest_ctx->host_ctx.host_saved_regs[11];
// Clear esr_el1 and return it.
host_ctx->__ss.__r[0] = guest_ctx->esr_el1.exchange(0);
#else
std::memcpy(guest_ctx->cpu_registers.data(), host_ctx.regs, sizeof(host_ctx.regs));
std::memcpy(guest_ctx->vector_registers.data(), fpctx->vregs, sizeof(fpctx->vregs));
guest_ctx->fpsr = fpctx->fpsr;
guest_ctx->fpcr = fpctx->fpcr;
guest_ctx->pstate = static_cast<u32>(host_ctx.pstate);
guest_ctx->pc = host_ctx.pc;
guest_ctx->sp = host_ctx.sp;
// Restore stack pointer.
host_ctx.sp = guest_ctx->host_ctx.host_sp;
// Restore host callee-saved registers. // Restore host callee-saved registers.
std::memcpy(&host_ctx.regs[19], guest_ctx->host_ctx.host_saved_regs.data(), std::memcpy(&CTX_X(19), guest_ctx->host_ctx.host_saved_regs.data(),
sizeof(guest_ctx->host_ctx.host_saved_regs)); sizeof(guest_ctx->host_ctx.host_saved_regs));
std::memcpy(&fpctx->vregs[8], guest_ctx->host_ctx.host_saved_vregs.data(), std::memcpy(&fpctx->vregs[8], guest_ctx->host_ctx.host_saved_vregs.data(),
sizeof(guest_ctx->host_ctx.host_saved_vregs)); sizeof(guest_ctx->host_ctx.host_saved_vregs));
// Return from the call on exit by setting pc to x30. // Return from the call on exit by setting pc to x30.
host_ctx.pc = guest_ctx->host_ctx.host_saved_regs[11]; CTX_PC = guest_ctx->host_ctx.host_saved_regs[11];
// Clear esr_el1 and return it. // Clear esr_el1 and return it.
host_ctx.regs[0] = guest_ctx->esr_el1.exchange(0); CTX_X(0) = guest_ctx->esr_el1.exchange(0);
#endif
} }
bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) { bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, void* raw_context) {
@ -182,7 +130,7 @@ bool ArmNce::HandleGuestAlignmentFault(GuestContext* guest_ctx, void* raw_info,
auto& memory = guest_ctx->system->ApplicationMemory(); auto& memory = guest_ctx->system->ApplicationMemory();
// Match and execute an instruction. // Match and execute an instruction.
auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx, fpctx); auto next_pc = MatchAndExecuteOneInstruction(memory, &host_ctx);
if (next_pc) { if (next_pc) {
host_ctx.pc = *next_pc; host_ctx.pc = *next_pc;
return true; return true;

View file

@ -790,13 +790,11 @@ bool InterpreterVisitor::LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3
return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt); return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt);
} }
#ifdef __APPLE__ std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context) {
std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context, std::span<u64, 31> regs(reinterpret_cast<u64*>(&CTX_X(0)), 31);
_STRUCT_ARM_NEON_STATE64* fpctx) { std::span<u128, 32> vregs(reinterpret_cast<u128*>(&CTX_Q(0)), 32);
std::span<u64, 31> regs(reinterpret_cast<u64*>(context->regs), 31); u64& sp = *reinterpret_cast<u64*>(&CTX_SP);
std::span<u128, 32> vregs(reinterpret_cast<u128*>(fpctx->__v), 32); const u64& pc = *reinterpret_cast<u64*>(&CTX_PC);
u64& sp = *reinterpret_cast<u64*>(&context->sp);
const u64& pc = *reinterpret_cast<u64*>(&context->pc);
InterpreterVisitor visitor(memory, regs, vregs, sp, pc); InterpreterVisitor visitor(memory, regs, vregs, sp, pc);
u32 instruction = memory.Read32(pc); u32 instruction = memory.Read32(pc);
bool was_executed = false; bool was_executed = false;
@ -807,23 +805,5 @@ std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, m
} }
return was_executed ? std::optional<u64>(pc + 4) : std::nullopt; return was_executed ? std::optional<u64>(pc + 4) : std::nullopt;
} }
#else
std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context,
fpsimd_context* fpctx) {
std::span<u64, 31> regs(reinterpret_cast<u64*>(context->regs), 31);
std::span<u128, 32> vregs(reinterpret_cast<u128*>(fpctx->vregs), 32);
u64& sp = *reinterpret_cast<u64*>(&context->sp);
const u64& pc = *reinterpret_cast<u64*>(&context->pc);
InterpreterVisitor visitor(memory, regs, vregs, sp, pc);
u32 instruction = memory.Read32(pc);
bool was_executed = false;
if (auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction)) {
was_executed = decoder->get().call(visitor, instruction);
} else {
LOG_ERROR(Core_ARM, "Unallocated encoding: {:#x}", instruction);
}
return was_executed ? std::optional<u64>(pc + 4) : std::nullopt;
}
#endif
} // namespace Core } // namespace Core

View file

@ -105,12 +105,6 @@ private:
const u64& m_pc; const u64& m_pc;
}; };
#ifdef __APPLE__ std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context);
std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context,
_STRUCT_ARM_NEON_STATE64* fpctx);
#else
std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context,
fpsimd_context* fpctx);
#endif
} // namespace Core } // namespace Core

View file

@ -6,6 +6,8 @@
* SPDX-License-Identifier: 0BSD * SPDX-License-Identifier: 0BSD
*/ */
#include "dynarmic/backend/exception_handler.h"
#include <cstring> #include <cstring>
#include <functional> #include <functional>
#include <memory> #include <memory>
@ -118,9 +120,10 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
CTX_DECLARE(raw_context); CTX_DECLARE(raw_context);
#if defined(ARCHITECTURE_x86_64) #if defined(ARCHITECTURE_x86_64)
{ {
std::shared_lock guard(sig_handler->code_block_infos_mutex); std::lock_guard<std::mutex> guard(sig_handler->code_block_infos_mutex);
if (auto const iter = sig_handler->FindCodeBlockInfo(CTX_RIP); iter != sig_handler->code_block_infos.end()) { const auto iter = sig_handler->FindCodeBlockInfo(CTX_RIP);
FakeCall fc = iter->second.cb(CTX_RIP); if (iter != sig_handler->code_block_infos.end()) {
FakeCall fc = iter->cb(CTX_RIP);
CTX_RSP -= sizeof(u64); CTX_RSP -= sizeof(u64);
*mcl::bit_cast<u64*>(CTX_RSP) = fc.ret_rip; *mcl::bit_cast<u64*>(CTX_RSP) = fc.ret_rip;
CTX_RIP = fc.call_rip; CTX_RIP = fc.call_rip;
@ -130,9 +133,10 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
fmt::print(stderr, "Unhandled {} at rip {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_RIP); fmt::print(stderr, "Unhandled {} at rip {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_RIP);
#elif defined(ARCHITECTURE_arm64) #elif defined(ARCHITECTURE_arm64)
{ {
std::shared_lock guard(sig_handler->code_block_infos_mutex); std::lock_guard<std::mutex> guard(sig_handler->code_block_infos_mutex);
if (const auto iter = sig_handler->FindCodeBlockInfo(CTX_PC); iter != sig_handler->code_block_infos.end()) { const auto iter = sig_handler->FindCodeBlockInfo(CTX_PC);
FakeCall fc = iter->second.cb(CTX_PC); if (iter != sig_handler->code_block_infos.end()) {
FakeCall fc = iter->cb(CTX_PC);
CTX_PC = fc.call_pc; CTX_PC = fc.call_pc;
return; return;
} }