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.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 180a4a096b..62cc07d448 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -380,12 +380,26 @@ void HELPER(exception_return)(CPUARMState *env)
env->exclusive_addr = -1;
+ /* We must squash the PSTATE.SS bit to zero unless both of the
+ * following hold:
+ * 1. debug exceptions are currently disabled
+ * 2. singlestep will be active in the EL we return to
+ * We check 1 here and 2 after we've done the pstate/cpsr write() to
+ * transition to the EL we're going to.
+ */
+ if (arm_generate_debug_exceptions(env)) {
+ spsr &= ~PSTATE_SS;
+ }
+
if (spsr & PSTATE_nRW) {
/* TODO: We currently assume EL1/2/3 are running in AArch64. */
env->aarch64 = 0;
new_el = 0;
env->uncached_cpsr = 0x10;
cpsr_write(env, spsr, ~0);
+ if (!arm_singlestep_active(env)) {
+ env->uncached_cpsr &= ~PSTATE_SS;
+ }
for (i = 0; i < 15; i++) {
env->regs[i] = env->xregs[i];
}
@@ -410,6 +424,9 @@ void HELPER(exception_return)(CPUARMState *env)
}
env->aarch64 = 1;
pstate_write(env, spsr);
+ if (!arm_singlestep_active(env)) {
+ env->pstate &= ~PSTATE_SS;
+ }
aarch64_restore_sp(env, new_el);
env->pc = env->elr_el[cur_el];
}
@@ -429,6 +446,9 @@ illegal_return:
spsr &= PSTATE_NZCV | PSTATE_DAIF;
spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
pstate_write(env, spsr);
+ if (!arm_singlestep_active(env)) {
+ env->pstate &= ~PSTATE_SS;
+ }
}
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.