diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index d6b69983..7fbe0778 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -5432,7 +5432,17 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) * - 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) { + uint32_t min_magic; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + /* Covers FNC_RETURN and EXC_RETURN magic */ + min_magic = FNC_RETURN_MIN_MAGIC; + } else { + /* EXC_RETURN magic only */ + min_magic = EXC_RETURN_MIN_MAGIC; + } + + if (dest >= min_magic) { /* 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 diff --git a/qemu/target/arm/internals.h b/qemu/target/arm/internals.h index 0d826bcf..527b9236 100644 --- a/qemu/target/arm/internals.h +++ b/qemu/target/arm/internals.h @@ -72,6 +72,13 @@ FIELD(V7M_EXCRET, DCRS, 5, 1) FIELD(V7M_EXCRET, S, 6, 1) FIELD(V7M_EXCRET, RES1, 7, 25) /* including the must-be-1 prefix */ +/* Minimum value which is a magic number for exception return */ +#define EXC_RETURN_MIN_MAGIC 0xff000000 +/* Minimum number which is a magic number for function or exception return + * when using v8M security extension + */ +#define FNC_RETURN_MIN_MAGIC 0xfefffffe + /* We use a few fake FSR values for internal purposes in M profile. * M profile cores don't have A/R format FSRs, but currently our * get_phys_addr() code assumes A/R profile and reports failures via diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index c95f4798..cf722ead 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -991,7 +991,8 @@ static inline void gen_bx_excret(DisasContext *s, TCGv_i32 var) * s->base.is_jmp that we need to do the rest of the work later. */ gen_bx(s, var); - if (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M)) { + if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY) || + (s->v7m_handler_mode && arm_dc_feature(s, ARM_FEATURE_M))) { s->base.is_jmp = DISAS_BX_EXCRET; } } @@ -1002,9 +1003,18 @@ static inline void gen_bx_excret_final_code(DisasContext *s) /* Generate the code to finish possible exception return and end the TB */ TCGLabel *excret_label = gen_new_label(tcg_ctx); + uint32_t min_magic; + + if (arm_dc_feature(s, ARM_FEATURE_M_SECURITY)) { + /* Covers FNC_RETURN and EXC_RETURN magic */ + min_magic = FNC_RETURN_MIN_MAGIC; + } else { + /* EXC_RETURN magic only */ + min_magic = EXC_RETURN_MIN_MAGIC; + } /* Is the new PC value in the magic range indicating exception return? */ - tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_GEU, tcg_ctx->cpu_R[15], 0xff000000, excret_label); + tcg_gen_brcondi_i32(tcg_ctx, TCG_COND_GEU, tcg_ctx->cpu_R[15], min_magic, excret_label); /* No: end the TB as we would for a DISAS_JMP */ if (is_singlestepping(s)) { gen_singlestep_exception(s);