aboutsummaryrefslogtreecommitdiff
path: root/target/arm/helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/helper.c')
-rw-r--r--target/arm/helper.c23
1 files changed, 18 insertions, 5 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index e801744673..142d301b65 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8182,7 +8182,7 @@ static bool v7m_push_stack(ARMCPU *cpu)
* should ignore further stack faults trying to process
* that derived exception.)
*/
- bool stacked_ok;
+ bool stacked_ok = true, limitviol = false;
CPUARMState *env = &cpu->env;
uint32_t xpsr = xpsr_read(env);
uint32_t frameptr = env->regs[13];
@@ -8213,7 +8213,14 @@ static bool v7m_push_stack(ARMCPU *cpu)
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
env->v7m.secure);
env->regs[13] = limit;
- return true;
+ /*
+ * We won't try to perform any further memory accesses but
+ * we must continue through the following code to check for
+ * permission faults during FPU state preservation, and we
+ * must update FPCCR if lazy stacking is enabled.
+ */
+ limitviol = true;
+ stacked_ok = false;
}
}
@@ -8222,7 +8229,7 @@ static bool v7m_push_stack(ARMCPU *cpu)
* (which may be taken in preference to the one we started with
* if it has higher priority).
*/
- stacked_ok =
+ stacked_ok = stacked_ok &&
v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, false) &&
v7m_stack_write(cpu, frameptr + 4, env->regs[1], mmu_idx, false) &&
v7m_stack_write(cpu, frameptr + 8, env->regs[2], mmu_idx, false) &&
@@ -8232,8 +8239,14 @@ static bool v7m_push_stack(ARMCPU *cpu)
v7m_stack_write(cpu, frameptr + 24, env->regs[15], mmu_idx, false) &&
v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, false);
- /* Update SP regardless of whether any of the stack accesses failed. */
- env->regs[13] = frameptr;
+ /*
+ * If we broke a stack limit then SP was already updated earlier;
+ * otherwise we update SP regardless of whether any of the stack
+ * accesses failed or we took some other kind of fault.
+ */
+ if (!limitviol) {
+ env->regs[13] = frameptr;
+ }
return !stacked_ok;
}