target/arm: Implement secure function return

Secure function return happens when a non-secure function has been
called using BLXNS and so has a particular magic LR value (either
0xfefffffe or 0xfeffffff). The function return via BX behaves
specially when the new PC value is this magic value, in the same
way that exception returns are handled.

Adjust our BX excret guards so that they recognize the function
return magic number as well, and perform the function-return
unstacking in do_v7m_exception_exit().

Backports commit d02a8698d7ae2bfed3b11fe5b064cb0aa406863b from qemu
This commit is contained in:
Peter Maydell 2018-03-05 03:33:39 -05:00 committed by Lioncash
parent e312993f1f
commit ee9b8a20c9
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
3 changed files with 30 additions and 3 deletions

View file

@ -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

View file

@ -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

View file

@ -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);