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{},
|
.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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue