summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-10-06 16:46:48 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-10-06 16:46:48 +0100
commit3f0cddeee1f266d43c956581f3050058360a810d (patch)
tree296d08b674ac4debe7505b9b5547ce1eb6894174
parent3919e60b6efd9a86a0e6ba637aa584222855ac3a (diff)
downloadqemu-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.c40
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);