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.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 1bab86cfd2..bee0f5ddb6 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6436,6 +6436,29 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
}
xpsr = ldl_phys(cs->as, frameptr + 0x1c);
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ /* For v8M we have to check whether the xPSR exception field
+ * matches the EXCRET value for return to handler/thread
+ * before we commit to changing the SP and xPSR.
+ */
+ bool will_be_handler = (xpsr & XPSR_EXCP) != 0;
+ if (return_to_handler != will_be_handler) {
+ /* Take an INVPC UsageFault on the current stack.
+ * By this point we will have switched to the security state
+ * for the background state, so this UsageFault will target
+ * that state.
+ */
+ armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE,
+ env->v7m.secure);
+ env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
+ v7m_exception_taken(cpu, excret);
+ qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing "
+ "stackframe: failed exception return integrity "
+ "check\n");
+ return;
+ }
+ }
+
/* Commit to consuming the stack frame */
frameptr += 0x20;
/* Undo stack alignment (the SPREALIGN bit indicates that the original
@@ -6455,12 +6478,13 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
/* The restored xPSR exception field will be zero if we're
* resuming in Thread mode. If that doesn't match what the
* exception return excret specified then this is a UsageFault.
+ * v7M requires we make this check here; v8M did it earlier.
*/
if (return_to_handler != arm_v7m_is_handler_mode(env)) {
- /* Take an INVPC UsageFault by pushing the stack again.
- * TODO: the v8M version of this code should target the
- * background state for this exception.
+ /* Take an INVPC UsageFault by pushing the stack again;
+ * we know we're v7M so this is never a Secure UsageFault.
*/
+ assert(!arm_feature(env, ARM_FEATURE_V8));
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false);
env->v7m.cfsr[env->v7m.secure] |= R_V7M_CFSR_INVPC_MASK;
v7m_push_stack(cpu);