diff options
Diffstat (limited to 'target-arm/op_helper.c')
-rw-r--r-- | target-arm/op_helper.c | 49 |
1 files changed, 43 insertions, 6 deletions
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 0b29b9dbf2..35912a1192 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -76,6 +76,43 @@ uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def, #if !defined(CONFIG_USER_ONLY) +static inline uint32_t merge_syn_data_abort(uint32_t template_syn, + unsigned int target_el, + bool same_el, + bool s1ptw, int is_write, + int fsc) +{ + uint32_t syn; + + /* ISV is only set for data aborts routed to EL2 and + * never for stage-1 page table walks faulting on stage 2. + * + * Furthermore, ISV is only set for certain kinds of load/stores. + * If the template syndrome does not have ISV set, we should leave + * it cleared. + * + * See ARMv8 specs, D7-1974: + * ISS encoding for an exception from a Data Abort, the + * ISV field. + */ + if (!(template_syn & ARM_EL_ISV) || target_el != 2 || s1ptw) { + syn = syn_data_abort_no_iss(same_el, + 0, 0, s1ptw, is_write == 1, fsc); + } else { + /* Fields: IL, ISV, SAS, SSE, SRT, SF and AR come from the template + * syndrome created at translation time. + * Now we create the runtime syndrome with the remaining fields. + */ + syn = syn_data_abort_with_iss(same_el, + 0, 0, 0, 0, 0, + 0, 0, s1ptw, is_write == 1, fsc, + false); + /* Merge the runtime syndrome with the template syndrome. */ + syn |= template_syn; + } + return syn; +} + /* try to fill the TLB and return an exception if error. If retaddr is * NULL, it means that the function was called in C code (i.e. not * from generated code or from helper.c) @@ -116,8 +153,8 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, syn = syn_insn_abort(same_el, 0, fi.s1ptw, syn); exc = EXCP_PREFETCH_ABORT; } else { - syn = syn_data_abort_no_iss(same_el, - 0, 0, fi.s1ptw, is_write == 1, syn); + syn = merge_syn_data_abort(env->exception.syndrome, target_el, + same_el, fi.s1ptw, is_write, syn); if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) { fsr |= (1 << 11); } @@ -138,6 +175,7 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write, CPUARMState *env = &cpu->env; int target_el; bool same_el; + uint32_t syn; if (retaddr) { /* now we have a real cpu fault */ @@ -162,10 +200,9 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write, env->exception.fsr |= (1 << 11); } - raise_exception(env, EXCP_DATA_ABORT, - syn_data_abort_no_iss(same_el, - 0, 0, 0, is_write == 1, 0x21), - target_el); + syn = merge_syn_data_abort(env->exception.syndrome, target_el, + same_el, 0, is_write, 0x21); + raise_exception(env, EXCP_DATA_ABORT, syn, target_el); } #endif /* !defined(CONFIG_USER_ONLY) */ |