diff options
Diffstat (limited to 'target-arm/translate.c')
-rw-r--r-- | target-arm/translate.c | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/target-arm/translate.c b/target-arm/translate.c index 29008a4b34..839f237c08 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -80,6 +80,7 @@ static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE]; conditional executions state has been updated. */ #define DISAS_WFI 4 #define DISAS_SWI 5 +#define DISAS_SMC 6 static TCGv_ptr cpu_env; /* We reuse the same 64-bit temporaries for efficiency. */ @@ -768,6 +769,12 @@ static inline void store_reg_from_load(CPUARMState *env, DisasContext *s, } } +static inline void gen_smc(CPUARMState *env, DisasContext *s) +{ + tcg_gen_movi_i32(cpu_R[15], s->pc); + s->is_jmp = DISAS_SMC; +} + static inline TCGv gen_ld8s(TCGv addr, int index) { TCGv tmp = tcg_temp_new_i32(); @@ -6726,8 +6733,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) } else if ((insn & 0x0fe00000) == 0x0c400000) { /* Coprocessor double register transfer. */ ARCH(5TE); + /* XXX doesn't belong in the trustzone patch: should just UNDEF? */ + cpu_abort(env, "unsupported coprocessor double register transfer\n"); } else if ((insn & 0x0f000010) == 0x0e000010) { /* Additional coprocessor register transfer. */ + if (!disas_coproc_insn(env, s, insn)) { + return; + } } else if ((insn & 0x0ff10020) == 0x01000000) { uint32_t mask; uint32_t val; @@ -6878,15 +6890,19 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) store_reg(s, rd, tmp); break; case 7: - /* SMC instruction (op1 == 3) - and undefined instructions (op1 == 0 || op1 == 2) - will trap */ - if (op1 != 1) { + if (op1 == 1) { + /* bkpt */ + ARCH(5); + gen_exception_insn(s, 4, EXCP_BKPT); + } else if (op1 == 3) { + /* smi/smc */ + if (!arm_feature(env, ARM_FEATURE_TRUSTZONE) || IS_USER(s)) { + goto illegal_op; + } + gen_smc(env, s); + } else { goto illegal_op; } - /* bkpt */ - ARCH(5); - gen_exception_insn(s, 4, EXCP_BKPT); break; case 0x8: /* signed multiply */ case 0xa: @@ -8541,8 +8557,12 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw goto illegal_op; if (insn & (1 << 26)) { - /* Secure monitor call (v6Z) */ - goto illegal_op; /* not implemented. */ + /* Secure monitor call / smc (v6Z) */ + if (!arm_feature(env, ARM_FEATURE_TRUSTZONE) + || IS_USER(s)) { + goto illegal_op; + } + gen_smc(env, s); } else { op = (insn >> 20) & 7; switch (op) { @@ -9872,6 +9892,8 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, gen_set_condexec(dc); if (dc->is_jmp == DISAS_SWI) { gen_exception(EXCP_SWI); + } else if (dc->is_jmp == DISAS_SMC) { + gen_exception(EXCP_SMC); } else { gen_exception(EXCP_DEBUG); } @@ -9884,6 +9906,8 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, gen_set_condexec(dc); if (dc->is_jmp == DISAS_SWI && !dc->condjmp) { gen_exception(EXCP_SWI); + } else if (dc->is_jmp == DISAS_SMC && !dc->condjmp) { + gen_exception(EXCP_SMC); } else { /* FIXME: Single stepping a WFI insn will not halt the CPU. */ @@ -9918,6 +9942,9 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, case DISAS_SWI: gen_exception(EXCP_SWI); break; + case DISAS_SMC: + gen_exception(EXCP_SMC); + break; } if (dc->condjmp) { gen_set_label(dc->condlabel); |