diff --git a/src/dynarmic/backend/arm64/a32_address_space.cpp b/src/dynarmic/backend/arm64/a32_address_space.cpp index 4ef74ca7..d1169fdd 100644 --- a/src/dynarmic/backend/arm64/a32_address_space.cpp +++ b/src/dynarmic/backend/arm64/a32_address_space.cpp @@ -276,6 +276,8 @@ EmitConfig A32AddressSpace::GetEmitConfig() { .tpidrro_el0{}, .tpidr_el0{}, + .check_halt_on_memory_access = conf.check_halt_on_memory_access, + .page_table_pointer = mcl::bit_cast(conf.page_table), .page_table_address_space_bits = 32, .page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits, @@ -293,6 +295,7 @@ EmitConfig A32AddressSpace::GetEmitConfig() { .emit_cond = EmitA32Cond, .emit_condition_failed_terminal = EmitA32ConditionFailedTerminal, .emit_terminal = EmitA32Terminal, + .emit_check_memory_abort = EmitA32CheckMemoryAbort, .state_nzcv_offset = offsetof(A32JitState, cpsr_nzcv), .state_fpsr_offset = offsetof(A32JitState, fpsr), diff --git a/src/dynarmic/backend/arm64/a64_address_space.cpp b/src/dynarmic/backend/arm64/a64_address_space.cpp index 3b8b6668..c52f4d05 100644 --- a/src/dynarmic/backend/arm64/a64_address_space.cpp +++ b/src/dynarmic/backend/arm64/a64_address_space.cpp @@ -396,6 +396,8 @@ EmitConfig A64AddressSpace::GetEmitConfig() { .tpidrro_el0 = conf.tpidrro_el0, .tpidr_el0 = conf.tpidr_el0, + .check_halt_on_memory_access = conf.check_halt_on_memory_access, + .page_table_pointer = mcl::bit_cast(conf.page_table), .page_table_address_space_bits = conf.page_table_address_space_bits, .page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits, @@ -413,6 +415,7 @@ EmitConfig A64AddressSpace::GetEmitConfig() { .emit_cond = EmitA64Cond, .emit_condition_failed_terminal = EmitA64ConditionFailedTerminal, .emit_terminal = EmitA64Terminal, + .emit_check_memory_abort = EmitA64CheckMemoryAbort, .state_nzcv_offset = offsetof(A64JitState, cpsr_nzcv), .state_fpsr_offset = offsetof(A64JitState, fpsr), diff --git a/src/dynarmic/backend/arm64/emit_arm64.h b/src/dynarmic/backend/arm64/emit_arm64.h index 13a0b317..1305733e 100644 --- a/src/dynarmic/backend/arm64/emit_arm64.h +++ b/src/dynarmic/backend/arm64/emit_arm64.h @@ -104,6 +104,9 @@ struct EmitConfig { const u64* tpidrro_el0; u64* tpidr_el0; + // Memory + bool check_halt_on_memory_access; + // Page table u64 page_table_pointer; size_t page_table_address_space_bits; @@ -125,6 +128,7 @@ struct EmitConfig { oaknut::Label (*emit_cond)(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Cond cond); void (*emit_condition_failed_terminal)(oaknut::CodeGenerator& code, EmitContext& ctx); void (*emit_terminal)(oaknut::CodeGenerator& code, EmitContext& ctx); + void (*emit_check_memory_abort)(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end); // State offsets size_t state_nzcv_offset; @@ -147,5 +151,7 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx); void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx); void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx); void EmitA64ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx); +void EmitA32CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end); +void EmitA64CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end); } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp index 3d43bcb7..f2b969f7 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a32.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a32.cpp @@ -14,6 +14,7 @@ #include "dynarmic/backend/arm64/fpsr_manager.h" #include "dynarmic/backend/arm64/reg_alloc.h" #include "dynarmic/frontend/A32/a32_types.h" +#include "dynarmic/interface/halt_reason.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/opcodes.h" @@ -144,6 +145,22 @@ void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ct EmitA32Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, location.SetSingleStepping(false), location.SingleStepping()); } +void EmitA32CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end) { + if (!ctx.conf.check_halt_on_memory_access) { + return; + } + + const A32::LocationDescriptor current_location{IR::LocationDescriptor{inst->GetArg(0).GetU64()}}; + + code.LDAR(Xscratch0, Xhalt); + code.TST(Xscratch0, static_cast(HaltReason::MemoryAbort)); + code.B(EQ, end); + EmitSetUpperLocationDescriptor(code, ctx, current_location, ctx.block.Location()); + code.MOV(Wscratch0, current_location.PC()); + code.STR(Wscratch0, Xstate, offsetof(A32JitState, regs) + sizeof(u32) * 15); + EmitRelocation(code, ctx, LinkTarget::ReturnFromRunCode); +} + template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); diff --git a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp index a686f555..dc2893ec 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp @@ -11,6 +11,7 @@ #include "dynarmic/backend/arm64/emit_arm64.h" #include "dynarmic/backend/arm64/emit_context.h" #include "dynarmic/backend/arm64/reg_alloc.h" +#include "dynarmic/interface/halt_reason.h" #include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/opcodes.h" @@ -120,6 +121,21 @@ void EmitA64ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ct EmitA64Terminal(code, ctx, IR::Term::LinkBlock{ctx.block.ConditionFailedLocation()}, location.SetSingleStepping(false), location.SingleStepping()); } +void EmitA64CheckMemoryAbort(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, oaknut::Label& end) { + if (!ctx.conf.check_halt_on_memory_access) { + return; + } + + const A64::LocationDescriptor current_location{IR::LocationDescriptor{inst->GetArg(0).GetU64()}}; + + code.LDAR(Xscratch0, Xhalt); + code.TST(Xscratch0, static_cast(HaltReason::MemoryAbort)); + code.B(EQ, end); + code.MOV(Xscratch0, current_location.PC()); + code.STR(Xscratch0, Xstate, offsetof(A64JitState, pc)); + EmitRelocation(code, ctx, LinkTarget::ReturnFromRunCode); +} + template<> void EmitIR(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst);