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 | 3f0cddeee1f266d43c956581f3050058360a810d (patch) | |
tree | 296d08b674ac4debe7505b9b5547ce1eb6894174 | |
parent | 3919e60b6efd9a86a0e6ba637aa584222855ac3a (diff) | |
download | qemu-3f0cddeee1f266d43c956581f3050058360a810d.tar.gz |
target/arm: Restore SPSEL to correct CONTROL register on exception return
On exception return for v8M, the SPSEL bit in the EXC_RETURN magic
value should be restored to the SPSEL bit in the CONTROL register
banked specified by the EXC_RETURN.ES bit.
Add write_v7m_control_spsel_for_secstate() which behaves like
write_v7m_control_spsel() but allows the caller to specify which
CONTROL bank to use, reimplement write_v7m_control_spsel() in
terms of it, and use it in exception return.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 1506092407-26985-6-git-send-email-peter.maydell@linaro.org
-rw-r--r-- | target/arm/helper.c | 40 |
1 files changed, 27 insertions, 13 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c index b82fc9f163..1bab86cfd2 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6059,28 +6059,42 @@ static bool v7m_using_psp(CPUARMState *env) env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK; } -/* Write to v7M CONTROL.SPSEL bit. This may change the current - * stack pointer between Main and Process stack pointers. +/* Write to v7M CONTROL.SPSEL bit for the specified security bank. + * This may change the current stack pointer between Main and Process + * stack pointers if it is done for the CONTROL register for the current + * security state. */ -static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel) +static void write_v7m_control_spsel_for_secstate(CPUARMState *env, + bool new_spsel, + bool secstate) { - uint32_t tmp; - bool new_is_psp, old_is_psp = v7m_using_psp(env); + bool old_is_psp = v7m_using_psp(env); - env->v7m.control[env->v7m.secure] = - deposit32(env->v7m.control[env->v7m.secure], + env->v7m.control[secstate] = + deposit32(env->v7m.control[secstate], R_V7M_CONTROL_SPSEL_SHIFT, R_V7M_CONTROL_SPSEL_LENGTH, new_spsel); - new_is_psp = v7m_using_psp(env); + if (secstate == env->v7m.secure) { + bool new_is_psp = v7m_using_psp(env); + uint32_t tmp; - if (old_is_psp != new_is_psp) { - tmp = env->v7m.other_sp; - env->v7m.other_sp = env->regs[13]; - env->regs[13] = tmp; + if (old_is_psp != new_is_psp) { + tmp = env->v7m.other_sp; + env->v7m.other_sp = env->regs[13]; + env->regs[13] = tmp; + } } } +/* Write to v7M CONTROL.SPSEL bit. This may change the current + * stack pointer between Main and Process stack pointers. + */ +static void write_v7m_control_spsel(CPUARMState *env, bool new_spsel) +{ + write_v7m_control_spsel_for_secstate(env, new_spsel, env->v7m.secure); +} + void write_v7m_exception(CPUARMState *env, uint32_t new_exc) { /* Write a new value to v7m.exception, thus transitioning into or out @@ -6379,7 +6393,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) * Handler mode (and will be until we write the new XPSR.Interrupt * field) this does not switch around the current stack pointer. */ - write_v7m_control_spsel(env, return_to_sp_process); + write_v7m_control_spsel_for_secstate(env, return_to_sp_process, exc_secure); switch_v7m_security_state(env, return_to_secure); |