backend/arm64: Implement Emit*CheckMemoryAbort
This commit is contained in:
parent
5353c5aa92
commit
c4226ba25b
5 changed files with 45 additions and 0 deletions
|
@ -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<u64>(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),
|
||||
|
|
|
@ -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<u64>(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),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<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<>
|
||||
void EmitIR<IR::Opcode::A32SetCheckBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
|
|
@ -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<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<>
|
||||
void EmitIR<IR::Opcode::A64SetCheckBit>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
|
|
Loading…
Reference in a new issue