From ce77ab917e3141ed4d51f07306b2adbb64633f5b Mon Sep 17 00:00:00 2001 From: Andrew Baumann Date: Thu, 3 Dec 2015 10:16:05 -0800 Subject: [PATCH] target-arm: change LDREX alignment checks to use existing MO_ALIGN mechanism ... wish I'd known about this earlier! --- target-arm/cpu.c | 1 + target-arm/helper.h | 1 - target-arm/internals.h | 4 ++++ target-arm/op_helper.c | 56 ++++++++++++++++++++++++++++++-------------------- target-arm/translate.c | 40 +++++++----------------------------- 5 files changed, 46 insertions(+), 56 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 30739fc0df..35a1f12661 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -1417,6 +1417,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->handle_mmu_fault = arm_cpu_handle_mmu_fault; #else cc->do_interrupt = arm_cpu_do_interrupt; + cc->do_unaligned_access = arm_cpu_do_unaligned_access; cc->get_phys_page_debug = arm_cpu_get_phys_page_debug; cc->vmsd = &vmstate_arm_cpu; cc->virtio_is_big_endian = arm_cpu_is_big_endian; diff --git a/target-arm/helper.h b/target-arm/helper.h index 16d0137e48..c2a85c722a 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -48,7 +48,6 @@ DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) DEF_HELPER_2(exception_internal, void, env, i32) DEF_HELPER_4(exception_with_syndrome, void, env, i32, i32, i32) -DEF_HELPER_2(alignment_exception, void, env, tl) DEF_HELPER_1(wfi, void, env) DEF_HELPER_1(wfe, void, env) DEF_HELPER_1(yield, void, env) diff --git a/target-arm/internals.h b/target-arm/internals.h index 17afe2a1f1..b925aaaa45 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -444,4 +444,8 @@ bool arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx, /* Return true if the translation regime is using LPAE format page tables */ bool arm_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx); +/* Raise a data fault alignment exception for the specified virtual address */ +void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write, + int is_user, uintptr_t retaddr); + #endif diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 5c4621065e..c6995cabdc 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -126,7 +126,40 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, raise_exception(env, exc, syn, target_el); } } -#endif + +/* Raise a data fault alignment exception for the specified virtual address */ +void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write, + int is_user, uintptr_t retaddr) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + int target_el; + bool same_el; + + if (retaddr) { + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr); + } + + target_el = exception_target_el(env); + same_el = (arm_current_el(env) == target_el); + + env->exception.vaddress = vaddr; + + /* the DFSR for an alignment fault depends on whether we're using + * the LPAE long descriptor format, or the short descriptor format */ + if (arm_regime_using_lpae_format(env, cpu_mmu_index(env, false))) { + env->exception.fsr = 0x21; + } else { + env->exception.fsr = 0x1; + } + + raise_exception(env, EXCP_DATA_ABORT, + syn_data_abort(same_el, 0, 0, 0, 0, 0x21), + target_el); +} + +#endif /* !defined(CONFIG_USER_ONLY) */ uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) { @@ -376,27 +409,6 @@ void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp, raise_exception(env, excp, syndrome, target_el); } -/* Raise a data fault alignment exception for the specified virtual address */ -void HELPER(alignment_exception)(CPUARMState *env, target_ulong vaddr) -{ - int target_el = exception_target_el(env); - bool same_el = (arm_current_el(env) != target_el); - - env->exception.vaddress = vaddr; - - /* the DFSR for an alignment fault depends on whether we're using - * the LPAE long descriptor format, or the short descriptor format */ - if (arm_regime_using_lpae_format(env, cpu_mmu_index(env, false))) { - env->exception.fsr = 0x21; - } else { - env->exception.fsr = 0x1; - } - - raise_exception(env, EXCP_DATA_ABORT, - syn_data_abort(same_el, 0, 0, 0, 0, 0x21), - target_el); -} - uint32_t HELPER(cpsr_read)(CPUARMState *env) { return cpsr_read(env) & ~(CPSR_EXEC | CPSR_RESERVED); diff --git a/target-arm/translate.c b/target-arm/translate.c index c05ea1f269..12dbfacaf2 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -37,7 +37,6 @@ #include "trace-tcg.h" -#define CONFIG_ALIGNMENT_EXCEPTIONS 1 #define ENABLE_ARCH_4T arm_dc_feature(s, ARM_FEATURE_V4T) #define ENABLE_ARCH_5 arm_dc_feature(s, ARM_FEATURE_V5) @@ -927,13 +926,13 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var) #define DO_GEN_LD(SUFF, OPC) \ static inline void gen_aa32_ld##SUFF(TCGv_i32 val, TCGv_i32 addr, int index) \ { \ - tcg_gen_qemu_ld_i32(val, addr, index, OPC); \ + tcg_gen_qemu_ld_i32(val, addr, index, (OPC)); \ } #define DO_GEN_ST(SUFF, OPC) \ static inline void gen_aa32_st##SUFF(TCGv_i32 val, TCGv_i32 addr, int index) \ { \ - tcg_gen_qemu_st_i32(val, addr, index, OPC); \ + tcg_gen_qemu_st_i32(val, addr, index, (OPC)); \ } static inline void gen_aa32_ld64(TCGv_i64 val, TCGv_i32 addr, int index) @@ -989,6 +988,9 @@ DO_GEN_LD(8u, MO_UB) DO_GEN_LD(16s, MO_TESW) DO_GEN_LD(16u, MO_TEUW) DO_GEN_LD(32u, MO_TEUL) +/* 'a' variants include an alignment check */ +DO_GEN_LD(16ua, MO_TEUW | MO_ALIGN) +DO_GEN_LD(32ua, MO_TEUL | MO_ALIGN) DO_GEN_ST(8, MO_UB) DO_GEN_ST(16, MO_TEUW) DO_GEN_ST(32, MO_TEUL) @@ -1059,28 +1061,6 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp, s->is_jmp = DISAS_JUMP; } -/* Emit an inline alignment check, which raises an exception if the given - * address is not aligned according to "size" (which must be a power of 2). */ -static void gen_alignment_check(DisasContext *s, int pc_offset, - target_ulong size, TCGv addr) -{ -#ifdef CONFIG_ALIGNMENT_EXCEPTIONS - TCGLabel *alignok_label = gen_new_label(); - TCGv tmp = tcg_temp_new(); - - /* check alignment, branch to alignok_label if aligned */ - tcg_gen_andi_tl(tmp, addr, size - 1); - tcg_gen_brcondi_tl(TCG_COND_EQ, tmp, 0, alignok_label); - - /* emit alignment exception */ - gen_set_pc_im(s, s->pc - pc_offset); - gen_helper_alignment_exception(cpu_env, addr); - - gen_set_label(alignok_label); - tcg_temp_free(tmp); -#endif -} - /* Force a TB lookup after an instruction that changes the CPU state. */ static inline void gen_lookup_tb(DisasContext *s) { @@ -7453,22 +7433,16 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2, s->is_ldex = true; - /* emit alignment check if needed */ - if (size != 0) { - /* NB: all LDREX variants (incl. thumb) occupy 4 bytes */ - gen_alignment_check(s, 4, (target_ulong)1 << size, addr); - } - switch (size) { case 0: gen_aa32_ld8u(tmp, addr, get_mem_index(s)); break; case 1: - gen_aa32_ld16u(tmp, addr, get_mem_index(s)); + gen_aa32_ld16ua(tmp, addr, get_mem_index(s)); break; case 2: case 3: - gen_aa32_ld32u(tmp, addr, get_mem_index(s)); + gen_aa32_ld32ua(tmp, addr, get_mem_index(s)); break; default: abort(); -- 2.11.4.GIT