aboutsummaryrefslogtreecommitdiff
path: root/target/arm/helper.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-09-07 13:54:54 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-09-07 13:54:54 +0100
commitfb602cb726b3ebdd01ef3b1732d74baf9fee7ec9 (patch)
treec703819a2a18f13e416d0800488a260fa7644788 /target/arm/helper.c
parent61fcd69b0db268e7612b07fadc436b93def91768 (diff)
target/arm: Implement BXNS, and banked stack pointers
Implement the BXNS v8M instruction, which is like BX but will do a jump-and-switch-to-NonSecure if the branch target address has bit 0 clear. This is the first piece of code which implements "switch to the other security state", so the commit also includes the code to switch the stack pointers around, which is the only complicated part of switching security state. BLXNS is more complicated than just "BXNS but set the link register", so we leave it for a separate commit. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 1503414539-28762-21-git-send-email-peter.maydell@linaro.org
Diffstat (limited to 'target/arm/helper.c')
-rw-r--r--target/arm/helper.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 00807b4053..329e5178d8 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -5870,6 +5870,12 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
return 0;
}
+void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
+{
+ /* translate.c should never generate calls here in user-only mode */
+ g_assert_not_reached();
+}
+
void switch_mode(CPUARMState *env, int mode)
{
ARMCPU *cpu = arm_env_get_cpu(env);
@@ -6044,6 +6050,18 @@ static uint32_t v7m_pop(CPUARMState *env)
return val;
}
+/* Return true if we're using the process stack pointer (not the MSP) */
+static bool v7m_using_psp(CPUARMState *env)
+{
+ /* Handler mode always uses the main stack; for thread mode
+ * the CONTROL.SPSEL bit determines the answer.
+ * Note that in v7M it is not possible to be in Handler mode with
+ * CONTROL.SPSEL non-zero, but in v8M it is, so we must check both.
+ */
+ return !arm_v7m_is_handler_mode(env) &&
+ env->v7m.control[env->v7m.secure] & R_V7M_CONTROL_SPSEL_MASK;
+}
+
/* Switch to V7M main or process stack pointer. */
static void switch_v7m_sp(CPUARMState *env, bool new_spsel)
{
@@ -6062,6 +6080,67 @@ static void switch_v7m_sp(CPUARMState *env, bool new_spsel)
}
}
+/* Switch M profile security state between NS and S */
+static void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
+{
+ uint32_t new_ss_msp, new_ss_psp;
+
+ if (env->v7m.secure == new_secstate) {
+ return;
+ }
+
+ /* All the banked state is accessed by looking at env->v7m.secure
+ * except for the stack pointer; rearrange the SP appropriately.
+ */
+ new_ss_msp = env->v7m.other_ss_msp;
+ new_ss_psp = env->v7m.other_ss_psp;
+
+ if (v7m_using_psp(env)) {
+ env->v7m.other_ss_psp = env->regs[13];
+ env->v7m.other_ss_msp = env->v7m.other_sp;
+ } else {
+ env->v7m.other_ss_msp = env->regs[13];
+ env->v7m.other_ss_psp = env->v7m.other_sp;
+ }
+
+ env->v7m.secure = new_secstate;
+
+ if (v7m_using_psp(env)) {
+ env->regs[13] = new_ss_psp;
+ env->v7m.other_sp = new_ss_msp;
+ } else {
+ env->regs[13] = new_ss_msp;
+ env->v7m.other_sp = new_ss_psp;
+ }
+}
+
+void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
+{
+ /* Handle v7M BXNS:
+ * - if the return value is a magic value, do exception return (like BX)
+ * - otherwise bit 0 of the return value is the target security state
+ */
+ if (dest >= 0xff000000) {
+ /* This is an exception return magic value; put it where
+ * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
+ * Note that if we ever add gen_ss_advance() singlestep support to
+ * M profile this should count as an "instruction execution complete"
+ * event (compare gen_bx_excret_final_code()).
+ */
+ env->regs[15] = dest & ~1;
+ env->thumb = dest & 1;
+ HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
+ /* notreached */
+ }
+
+ /* translate.c should have made BXNS UNDEF unless we're secure */
+ assert(env->v7m.secure);
+
+ switch_v7m_security_state(env, dest & 1);
+ env->thumb = 1;
+ env->regs[15] = dest & ~1;
+}
+
static uint32_t arm_v7m_load_vector(ARMCPU *cpu)
{
CPUState *cs = CPU(cpu);