diff options
Diffstat (limited to 'target-arm/op_helper.c')
-rw-r--r-- | target-arm/op_helper.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 6cd54c8f7a..e42d287d9c 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -126,7 +126,45 @@ 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; + } + + if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) { + env->exception.fsr |= (1 << 11); + } + + raise_exception(env, EXCP_DATA_ABORT, + syn_data_abort(same_el, 0, 0, 0, is_write == 1, 0x21), + target_el); +} + +#endif /* !defined(CONFIG_USER_ONLY) */ uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) { |