diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 9e6d9a45..5d1d6632 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_aarch64 #define gen_helper_usubaddx gen_helper_usubaddx_aarch64 #define gen_helper_uxtb16 gen_helper_uxtb16_aarch64 +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_aarch64 #define gen_helper_v7m_bxns gen_helper_v7m_bxns_aarch64 #define gen_helper_v7m_mrs gen_helper_v7m_mrs_aarch64 #define gen_helper_v7m_msr gen_helper_v7m_msr_aarch64 @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_aarch64 #define helper_usubaddx helper_usubaddx_aarch64 #define helper_uxtb16 helper_uxtb16_aarch64 +#define helper_v7m_blxns helper_v7m_blxns_aarch64 #define helper_v7m_bxns helper_v7m_bxns_aarch64 #define helper_v7m_mrs helper_v7m_mrs_aarch64 #define helper_v7m_msr helper_v7m_msr_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index d0cf6f84..0158fc84 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_aarch64eb #define gen_helper_usubaddx gen_helper_usubaddx_aarch64eb #define gen_helper_uxtb16 gen_helper_uxtb16_aarch64eb +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_aarch64eb #define gen_helper_v7m_bxns gen_helper_v7m_bxns_aarch64eb #define gen_helper_v7m_mrs gen_helper_v7m_mrs_aarch64eb #define gen_helper_v7m_msr gen_helper_v7m_msr_aarch64eb @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_aarch64eb #define helper_usubaddx helper_usubaddx_aarch64eb #define helper_uxtb16 helper_uxtb16_aarch64eb +#define helper_v7m_blxns helper_v7m_blxns_aarch64eb #define helper_v7m_bxns helper_v7m_bxns_aarch64eb #define helper_v7m_mrs helper_v7m_mrs_aarch64eb #define helper_v7m_msr helper_v7m_msr_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index 4abb1f23..a020fea5 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_arm #define gen_helper_usubaddx gen_helper_usubaddx_arm #define gen_helper_uxtb16 gen_helper_uxtb16_arm +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_arm #define gen_helper_v7m_bxns gen_helper_v7m_bxns_arm #define gen_helper_v7m_mrs gen_helper_v7m_mrs_arm #define gen_helper_v7m_msr gen_helper_v7m_msr_arm @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_arm #define helper_usubaddx helper_usubaddx_arm #define helper_uxtb16 helper_uxtb16_arm +#define helper_v7m_blxns helper_v7m_blxns_arm #define helper_v7m_bxns helper_v7m_bxns_arm #define helper_v7m_mrs helper_v7m_mrs_arm #define helper_v7m_msr helper_v7m_msr_arm diff --git a/qemu/armeb.h b/qemu/armeb.h index d2667e1d..e91ffb6e 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_armeb #define gen_helper_usubaddx gen_helper_usubaddx_armeb #define gen_helper_uxtb16 gen_helper_uxtb16_armeb +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_armeb #define gen_helper_v7m_bxns gen_helper_v7m_bxns_armeb #define gen_helper_v7m_mrs gen_helper_v7m_mrs_armeb #define gen_helper_v7m_msr gen_helper_v7m_msr_armeb @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_armeb #define helper_usubaddx helper_usubaddx_armeb #define helper_uxtb16 helper_uxtb16_armeb +#define helper_v7m_blxns helper_v7m_blxns_armeb #define helper_v7m_bxns helper_v7m_bxns_armeb #define helper_v7m_mrs helper_v7m_mrs_armeb #define helper_v7m_msr helper_v7m_msr_armeb diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 65464905..9e710db7 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -1100,6 +1100,7 @@ symbols = ( 'gen_helper_usub8', 'gen_helper_usubaddx', 'gen_helper_uxtb16', + 'gen_helper_v7m_blxns', 'gen_helper_v7m_bxns', 'gen_helper_v7m_mrs', 'gen_helper_v7m_msr', @@ -2060,6 +2061,7 @@ symbols = ( 'helper_usub8', 'helper_usubaddx', 'helper_uxtb16', + 'helper_v7m_blxns', 'helper_v7m_bxns', 'helper_v7m_mrs', 'helper_v7m_msr', diff --git a/qemu/m68k.h b/qemu/m68k.h index 8b2102f3..67b41f55 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_m68k #define gen_helper_usubaddx gen_helper_usubaddx_m68k #define gen_helper_uxtb16 gen_helper_uxtb16_m68k +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_m68k #define gen_helper_v7m_bxns gen_helper_v7m_bxns_m68k #define gen_helper_v7m_mrs gen_helper_v7m_mrs_m68k #define gen_helper_v7m_msr gen_helper_v7m_msr_m68k @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_m68k #define helper_usubaddx helper_usubaddx_m68k #define helper_uxtb16 helper_uxtb16_m68k +#define helper_v7m_blxns helper_v7m_blxns_m68k #define helper_v7m_bxns helper_v7m_bxns_m68k #define helper_v7m_mrs helper_v7m_mrs_m68k #define helper_v7m_msr helper_v7m_msr_m68k diff --git a/qemu/mips.h b/qemu/mips.h index 86d3f3a3..de47ce51 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_mips #define gen_helper_usubaddx gen_helper_usubaddx_mips #define gen_helper_uxtb16 gen_helper_uxtb16_mips +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_mips #define gen_helper_v7m_bxns gen_helper_v7m_bxns_mips #define gen_helper_v7m_mrs gen_helper_v7m_mrs_mips #define gen_helper_v7m_msr gen_helper_v7m_msr_mips @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_mips #define helper_usubaddx helper_usubaddx_mips #define helper_uxtb16 helper_uxtb16_mips +#define helper_v7m_blxns helper_v7m_blxns_mips #define helper_v7m_bxns helper_v7m_bxns_mips #define helper_v7m_mrs helper_v7m_mrs_mips #define helper_v7m_msr helper_v7m_msr_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index b2c8614f..8f404e5b 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_mips64 #define gen_helper_usubaddx gen_helper_usubaddx_mips64 #define gen_helper_uxtb16 gen_helper_uxtb16_mips64 +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_mips64 #define gen_helper_v7m_bxns gen_helper_v7m_bxns_mips64 #define gen_helper_v7m_mrs gen_helper_v7m_mrs_mips64 #define gen_helper_v7m_msr gen_helper_v7m_msr_mips64 @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_mips64 #define helper_usubaddx helper_usubaddx_mips64 #define helper_uxtb16 helper_uxtb16_mips64 +#define helper_v7m_blxns helper_v7m_blxns_mips64 #define helper_v7m_bxns helper_v7m_bxns_mips64 #define helper_v7m_mrs helper_v7m_mrs_mips64 #define helper_v7m_msr helper_v7m_msr_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index a34d095e..3d24a5a8 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_mips64el #define gen_helper_usubaddx gen_helper_usubaddx_mips64el #define gen_helper_uxtb16 gen_helper_uxtb16_mips64el +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_mips64el #define gen_helper_v7m_bxns gen_helper_v7m_bxns_mips64el #define gen_helper_v7m_mrs gen_helper_v7m_mrs_mips64el #define gen_helper_v7m_msr gen_helper_v7m_msr_mips64el @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_mips64el #define helper_usubaddx helper_usubaddx_mips64el #define helper_uxtb16 helper_uxtb16_mips64el +#define helper_v7m_blxns helper_v7m_blxns_mips64el #define helper_v7m_bxns helper_v7m_bxns_mips64el #define helper_v7m_mrs helper_v7m_mrs_mips64el #define helper_v7m_msr helper_v7m_msr_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 31b75565..6e66ca94 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_mipsel #define gen_helper_usubaddx gen_helper_usubaddx_mipsel #define gen_helper_uxtb16 gen_helper_uxtb16_mipsel +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_mipsel #define gen_helper_v7m_bxns gen_helper_v7m_bxns_mipsel #define gen_helper_v7m_mrs gen_helper_v7m_mrs_mipsel #define gen_helper_v7m_msr gen_helper_v7m_msr_mipsel @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_mipsel #define helper_usubaddx helper_usubaddx_mipsel #define helper_uxtb16 helper_uxtb16_mipsel +#define helper_v7m_blxns helper_v7m_blxns_mipsel #define helper_v7m_bxns helper_v7m_bxns_mipsel #define helper_v7m_mrs helper_v7m_mrs_mipsel #define helper_v7m_msr helper_v7m_msr_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 516caf7f..94fb2dbf 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_powerpc #define gen_helper_usubaddx gen_helper_usubaddx_powerpc #define gen_helper_uxtb16 gen_helper_uxtb16_powerpc +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_powerpc #define gen_helper_v7m_bxns gen_helper_v7m_bxns_powerpc #define gen_helper_v7m_mrs gen_helper_v7m_mrs_powerpc #define gen_helper_v7m_msr gen_helper_v7m_msr_powerpc @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_powerpc #define helper_usubaddx helper_usubaddx_powerpc #define helper_uxtb16 helper_uxtb16_powerpc +#define helper_v7m_blxns helper_v7m_blxns_powerpc #define helper_v7m_bxns helper_v7m_bxns_powerpc #define helper_v7m_mrs helper_v7m_mrs_powerpc #define helper_v7m_msr helper_v7m_msr_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index 6e2da815..1b396dee 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_sparc #define gen_helper_usubaddx gen_helper_usubaddx_sparc #define gen_helper_uxtb16 gen_helper_uxtb16_sparc +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_sparc #define gen_helper_v7m_bxns gen_helper_v7m_bxns_sparc #define gen_helper_v7m_mrs gen_helper_v7m_mrs_sparc #define gen_helper_v7m_msr gen_helper_v7m_msr_sparc @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_sparc #define helper_usubaddx helper_usubaddx_sparc #define helper_uxtb16 helper_uxtb16_sparc +#define helper_v7m_blxns helper_v7m_blxns_sparc #define helper_v7m_bxns helper_v7m_bxns_sparc #define helper_v7m_mrs helper_v7m_mrs_sparc #define helper_v7m_msr helper_v7m_msr_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 3f936e95..b95fd1f3 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_sparc64 #define gen_helper_usubaddx gen_helper_usubaddx_sparc64 #define gen_helper_uxtb16 gen_helper_uxtb16_sparc64 +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_sparc64 #define gen_helper_v7m_bxns gen_helper_v7m_bxns_sparc64 #define gen_helper_v7m_mrs gen_helper_v7m_mrs_sparc64 #define gen_helper_v7m_msr gen_helper_v7m_msr_sparc64 @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_sparc64 #define helper_usubaddx helper_usubaddx_sparc64 #define helper_uxtb16 helper_uxtb16_sparc64 +#define helper_v7m_blxns helper_v7m_blxns_sparc64 #define helper_v7m_bxns helper_v7m_bxns_sparc64 #define helper_v7m_mrs helper_v7m_mrs_sparc64 #define helper_v7m_msr helper_v7m_msr_sparc64 diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index a0b1a5ca..d6b69983 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -5156,6 +5156,12 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) g_assert_not_reached(); } +void HELPER(v7m_blxns)(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); @@ -5447,6 +5453,59 @@ void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest) env->regs[15] = dest & ~1; } +void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest) +{ + /* Handle v7M BLXNS: + * - bit 0 of the destination address is the target security state + */ + + /* At this point regs[15] is the address just after the BLXNS */ + uint32_t nextinst = env->regs[15] | 1; + uint32_t sp = env->regs[13] - 8; + uint32_t saved_psr; + + /* translate.c will have made BLXNS UNDEF unless we're secure */ + assert(env->v7m.secure); + + if (dest & 1) { + /* target is Secure, so this is just a normal BLX, + * except that the low bit doesn't indicate Thumb/not. + */ + env->regs[14] = nextinst; + env->thumb = 1; + env->regs[15] = dest & ~1; + return; + } + + /* Target is non-secure: first push a stack frame */ + if (!QEMU_IS_ALIGNED(sp, 8)) { + qemu_log_mask(LOG_GUEST_ERROR, + "BLXNS with misaligned SP is UNPREDICTABLE\n"); + } + + saved_psr = env->v7m.exception; + if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) { + saved_psr |= XPSR_SFPA; + } + + /* Note that these stores can throw exceptions on MPU faults */ + cpu_stl_data(env, sp, nextinst); + cpu_stl_data(env, sp + 4, saved_psr); + + env->regs[13] = sp; + env->regs[14] = 0xfeffffff; + if (arm_v7m_is_handler_mode(env)) { + /* Write a dummy value to IPSR, to avoid leaking the current secure + * exception number to non-secure code. This is guaranteed not + * to cause write_v7m_exception() to actually change stacks. + */ + write_v7m_exception(env, 1); + } + switch_v7m_security_state(env, 0); + env->thumb = 1; + env->regs[15] = dest; +} + static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode, bool spsel) { diff --git a/qemu/target/arm/helper.h b/qemu/target/arm/helper.h index f16dfe64..5887cd70 100644 --- a/qemu/target/arm/helper.h +++ b/qemu/target/arm/helper.h @@ -66,6 +66,7 @@ DEF_HELPER_3(v7m_msr, void, env, i32, i32) DEF_HELPER_2(v7m_mrs, i32, env, i32) DEF_HELPER_2(v7m_bxns, void, env, i32) +DEF_HELPER_2(v7m_blxns, void, env, i32) DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32) DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) diff --git a/qemu/target/arm/internals.h b/qemu/target/arm/internals.h index 18b50caf..0d826bcf 100644 --- a/qemu/target/arm/internals.h +++ b/qemu/target/arm/internals.h @@ -60,6 +60,7 @@ static inline bool excp_is_internal(int excp) FIELD(V7M_CONTROL, NPRIV, 0, 1) FIELD(V7M_CONTROL, SPSEL, 1, 1) FIELD(V7M_CONTROL, FPCA, 2, 1) +FIELD(V7M_CONTROL, SFPA, 3, 1) /* Bit definitions for v7M exception return payload */ FIELD(V7M_EXCRET, ES, 0, 1) diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index c46b0801..c95f4798 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -1047,6 +1047,21 @@ static inline void gen_bxns(DisasContext *s, int rm) s->base.is_jmp = DISAS_EXIT; } +static inline void gen_blxns(DisasContext *s, int rm) +{ + TCGContext *tcg_ctx = s->uc->tcg_ctx; + TCGv_i32 var = load_reg(s, rm); + + /* We don't need to sync condexec state, for the same reason as bxns. + * We do however need to set the PC, because the blxns helper reads it. + * The blxns helper may throw an exception. + */ + gen_set_pc_im(s, s->pc); + gen_helper_v7m_blxns(tcg_ctx, tcg_ctx->cpu_env, var); + tcg_temp_free_i32(tcg_ctx, var); + s->base.is_jmp = DISAS_EXIT; +} + /* Variant of store_reg which uses branch&exchange logic when storing to r15 in ARM architecture v7 and above. The source must be a temporary and will be marked as dead. */ @@ -11432,8 +11447,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq goto undef; } if (link) { - /* BLXNS: not yet implemented */ - goto undef; + gen_blxns(s, rm); } else { gen_bxns(s, rm); } diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 1a80a72d..e2a45a31 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -1094,6 +1094,7 @@ #define gen_helper_usub8 gen_helper_usub8_x86_64 #define gen_helper_usubaddx gen_helper_usubaddx_x86_64 #define gen_helper_uxtb16 gen_helper_uxtb16_x86_64 +#define gen_helper_v7m_blxns gen_helper_v7m_blxns_x86_64 #define gen_helper_v7m_bxns gen_helper_v7m_bxns_x86_64 #define gen_helper_v7m_mrs gen_helper_v7m_mrs_x86_64 #define gen_helper_v7m_msr gen_helper_v7m_msr_x86_64 @@ -2054,6 +2055,7 @@ #define helper_usub8 helper_usub8_x86_64 #define helper_usubaddx helper_usubaddx_x86_64 #define helper_uxtb16 helper_uxtb16_x86_64 +#define helper_v7m_blxns helper_v7m_blxns_x86_64 #define helper_v7m_bxns helper_v7m_bxns_x86_64 #define helper_v7m_mrs helper_v7m_mrs_x86_64 #define helper_v7m_msr helper_v7m_msr_x86_64