aboutsummaryrefslogtreecommitdiff
path: root/target-arm/op_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-arm/op_helper.c')
-rw-r--r--target-arm/op_helper.c49
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) */