diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-10-06 16:46:48 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-10-06 16:46:48 +0100 |
commit | 907bedb3f3ce134c149599bd9cb61856d811b8ca (patch) | |
tree | 20fe088281fdb5ae7ede849dd629b1b3b560de3f | |
parent | bfb2eb52788b9605ef2fc9bc72683d4299117fde (diff) |
target/arm: Add support for restoring v8M additional state context
For v8M, exceptions from Secure to Non-Secure state will save
callee-saved registers to the exception frame as well as the
caller-saved registers. Add support for unstacking these
registers in exception exit when necessary.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 1506092407-26985-12-git-send-email-peter.maydell@linaro.org
-rw-r--r-- | target/arm/helper.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c index 4aa32d0a0e..f93a2143da 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6463,6 +6463,36 @@ static void do_v7m_exception_exit(ARMCPU *cpu) "for destination state is UNPREDICTABLE\n"); } + /* Do we need to pop callee-saved registers? */ + if (return_to_secure && + ((excret & R_V7M_EXCRET_ES_MASK) == 0 || + (excret & R_V7M_EXCRET_DCRS_MASK) == 0)) { + uint32_t expected_sig = 0xfefa125b; + uint32_t actual_sig = ldl_phys(cs->as, frameptr); + + if (expected_sig != actual_sig) { + /* Take a SecureFault on the current stack */ + env->v7m.sfsr |= R_V7M_SFSR_INVIS_MASK; + armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); + v7m_exception_taken(cpu, excret); + qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing " + "stackframe: failed exception return integrity " + "signature check\n"); + return; + } + + env->regs[4] = ldl_phys(cs->as, frameptr + 0x8); + env->regs[5] = ldl_phys(cs->as, frameptr + 0xc); + env->regs[6] = ldl_phys(cs->as, frameptr + 0x10); + env->regs[7] = ldl_phys(cs->as, frameptr + 0x14); + env->regs[8] = ldl_phys(cs->as, frameptr + 0x18); + env->regs[9] = ldl_phys(cs->as, frameptr + 0x1c); + env->regs[10] = ldl_phys(cs->as, frameptr + 0x20); + env->regs[11] = ldl_phys(cs->as, frameptr + 0x24); + + frameptr += 0x28; + } + /* Pop registers. TODO: make these accesses use the correct * attributes and address space (S/NS, priv/unpriv) and handle * memory transaction failures. |