backend/arm64: Implement Emit*CheckMemoryAbort

This commit is contained in:
Merry 2022-12-10 18:38:53 +00:00
parent 5353c5aa92
commit c4226ba25b
5 changed files with 45 additions and 0 deletions

View file

@ -276,6 +276,8 @@ EmitConfig A32AddressSpace::GetEmitConfig() {
.tpidrro_el0{}, .tpidrro_el0{},
.tpidr_el0{}, .tpidr_el0{},
.check_halt_on_memory_access = conf.check_halt_on_memory_access,
.page_table_pointer = mcl::bit_cast<u64>(conf.page_table), .page_table_pointer = mcl::bit_cast<u64>(conf.page_table),
.page_table_address_space_bits = 32, .page_table_address_space_bits = 32,
.page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits, .page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits,
@ -293,6 +295,7 @@ EmitConfig A32AddressSpace::GetEmitConfig() {
.emit_cond = EmitA32Cond, .emit_cond = EmitA32Cond,
.emit_condition_failed_terminal = EmitA32ConditionFailedTerminal, .emit_condition_failed_terminal = EmitA32ConditionFailedTerminal,
.emit_terminal = EmitA32Terminal, .emit_terminal = EmitA32Terminal,
.emit_check_memory_abort = EmitA32CheckMemoryAbort,
.state_nzcv_offset = offsetof(A32JitState, cpsr_nzcv), .state_nzcv_offset = offsetof(A32JitState, cpsr_nzcv),
.state_fpsr_offset = offsetof(A32JitState, fpsr), .state_fpsr_offset = offsetof(A32JitState, fpsr),

View file

@ -396,6 +396,8 @@ EmitConfig A64AddressSpace::GetEmitConfig() {
.tpidrro_el0 = conf.tpidrro_el0, .tpidrro_el0 = conf.tpidrro_el0,
.tpidr_el0 = conf.tpidr_el0, .tpidr_el0 = conf.tpidr_el0,
.check_halt_on_memory_access = conf.check_halt_on_memory_access,
.page_table_pointer = mcl::bit_cast<u64>(conf.page_table), .page_table_pointer = mcl::bit_cast<u64>(conf.page_table),
.page_table_address_space_bits = conf.page_table_address_space_bits, .page_table_address_space_bits = conf.page_table_address_space_bits,
.page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits, .page_table_pointer_mask_bits = conf.page_table_pointer_mask_bits,
@ -413,6 +415,7 @@ EmitConfig A64AddressSpace::GetEmitConfig() {
.emit_cond = EmitA64Cond, .emit_cond = EmitA64Cond,
.emit_condition_failed_terminal = EmitA64ConditionFailedTerminal, .emit_condition_failed_terminal = EmitA64ConditionFailedTerminal,
.emit_terminal = EmitA64Terminal, .emit_terminal = EmitA64Terminal,
.emit_check_memory_abort = EmitA64CheckMemoryAbort,
.state_nzcv_offset = offsetof(A64JitState, cpsr_nzcv), .state_nzcv_offset = offsetof(A64JitState, cpsr_nzcv),
.state_fpsr_offset = offsetof(A64JitState, fpsr), .state_fpsr_offset = offsetof(A64JitState, fpsr),

View file

@ -104,6 +104,9 @@ struct EmitConfig {
const u64* tpidrro_el0; const u64* tpidrro_el0;
u64* tpidr_el0; u64* tpidr_el0;
// Memory
bool check_halt_on_memory_access;
// Page table // Page table
u64 page_table_pointer; u64 page_table_pointer;
size_t page_table_address_space_bits; 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); oaknut::Label (*emit_cond)(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Cond cond);
void (*emit_condition_failed_terminal)(oaknut::CodeGenerator& code, EmitContext& ctx); void (*emit_condition_failed_terminal)(oaknut::CodeGenerator& code, EmitContext& ctx);
void (*emit_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 // State offsets
size_t state_nzcv_offset; size_t state_nzcv_offset;
@ -147,5 +151,7 @@ void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx);
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx); void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx);
void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx); void EmitA32ConditionFailedTerminal(oaknut::CodeGenerator& code, EmitContext& ctx);
void EmitA64ConditionFailedTerminal(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 } // namespace Dynarmic::Backend::Arm64

View file

@ -14,6 +14,7 @@
#include "dynarmic/backend/arm64/fpsr_manager.h" #include "dynarmic/backend/arm64/fpsr_manager.h"
#include "dynarmic/backend/arm64/reg_alloc.h" #include "dynarmic/backend/arm64/reg_alloc.h"
#include "dynarmic/frontend/A32/a32_types.h" #include "dynarmic/frontend/A32/a32_types.h"
#include "dynarmic/interface/halt_reason.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.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()); 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<u32>(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<> template<>
void EmitIR<IR::Opcode::A32SetCheckBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A32SetCheckBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);

View file

@ -11,6 +11,7 @@
#include "dynarmic/backend/arm64/emit_arm64.h" #include "dynarmic/backend/arm64/emit_arm64.h"
#include "dynarmic/backend/arm64/emit_context.h" #include "dynarmic/backend/arm64/emit_context.h"
#include "dynarmic/backend/arm64/reg_alloc.h" #include "dynarmic/backend/arm64/reg_alloc.h"
#include "dynarmic/interface/halt_reason.h"
#include "dynarmic/ir/basic_block.h" #include "dynarmic/ir/basic_block.h"
#include "dynarmic/ir/microinstruction.h" #include "dynarmic/ir/microinstruction.h"
#include "dynarmic/ir/opcodes.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()); 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<u32>(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<> template<>
void EmitIR<IR::Opcode::A64SetCheckBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { void EmitIR<IR::Opcode::A64SetCheckBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);