diff mbox

[PULL,34/45] target-arm: A64: Implement MSR (immediate) instructions

Message ID 1393437755-23586-35-git-send-email-peter.maydell@linaro.org
State Accepted
Commit 9cfa0b4e4c3076683b6c528a1a3b43d5a202a497
Headers show

Commit Message

Peter Maydell Feb. 26, 2014, 6:02 p.m. UTC
Implement the MSR (immediate) instructions, which can update the
PSTATE SP and DAIF fields.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---
 target-arm/helper.h        |  2 ++
 target-arm/op_helper.c     | 25 +++++++++++++++++++++++++
 target-arm/translate-a64.c | 25 ++++++++++++++++++++++++-
 3 files changed, 51 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/target-arm/helper.h b/target-arm/helper.h
index 19bd620..4a063c1 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -63,6 +63,8 @@  DEF_HELPER_2(get_cp_reg, i32, env, ptr)
 DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
 DEF_HELPER_2(get_cp_reg64, i64, env, ptr)
 
+DEF_HELPER_3(msr_i_pstate, void, env, i32, i32)
+
 DEF_HELPER_2(get_r13_banked, i32, env, i32)
 DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
 
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index eb0fccd..7d06d2f 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -319,6 +319,31 @@  uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
     return ri->readfn(env, ri);
 }
 
+void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
+{
+    /* MSR_i to update PSTATE. This is OK from EL0 only if UMA is set.
+     * Note that SPSel is never OK from EL0; we rely on handle_msr_i()
+     * to catch that case at translate time.
+     */
+    if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
+        raise_exception(env, EXCP_UDEF);
+    }
+
+    switch (op) {
+    case 0x05: /* SPSel */
+        env->pstate = deposit32(env->pstate, 0, 1, imm);
+        break;
+    case 0x1e: /* DAIFSet */
+        env->daif |= (imm << 6) & PSTATE_DAIF;
+        break;
+    case 0x1f: /* DAIFClear */
+        env->daif &= ~((imm << 6) & PSTATE_DAIF);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+}
+
 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
    The only way to do that in TCG is a conditional branch, which clobbers
    all our temporaries.  For now implement these as helper functions.  */
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 2f47ec5..08ac659 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1128,7 +1128,30 @@  static void handle_sync(DisasContext *s, uint32_t insn,
 static void handle_msr_i(DisasContext *s, uint32_t insn,
                          unsigned int op1, unsigned int op2, unsigned int crm)
 {
-    unsupported_encoding(s, insn);
+    int op = op1 << 3 | op2;
+    switch (op) {
+    case 0x05: /* SPSel */
+        if (s->current_pl == 0) {
+            unallocated_encoding(s);
+            return;
+        }
+        /* fall through */
+    case 0x1e: /* DAIFSet */
+    case 0x1f: /* DAIFClear */
+    {
+        TCGv_i32 tcg_imm = tcg_const_i32(crm);
+        TCGv_i32 tcg_op = tcg_const_i32(op);
+        gen_a64_set_pc_im(s->pc - 4);
+        gen_helper_msr_i_pstate(cpu_env, tcg_op, tcg_imm);
+        tcg_temp_free_i32(tcg_imm);
+        tcg_temp_free_i32(tcg_op);
+        s->is_jmp = DISAS_UPDATE;
+        break;
+    }
+    default:
+        unallocated_encoding(s);
+        return;
+    }
 }
 
 static void gen_get_nzcv(TCGv_i64 tcg_rt)