diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ec2a7716ce..7bc97fece9 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3171,6 +3171,7 @@ FIELD(TBFLAG_ANY, FPEXC_EL, 8, 2) FIELD(TBFLAG_ANY, ALIGN_MEM, 10, 1) FIELD(TBFLAG_ANY, PSTATE__IL, 11, 1) FIELD(TBFLAG_ANY, FGT_ACTIVE, 12, 1) +FIELD(TBFLAG_ANY, FGT_SVC, 13, 1) /* * Bit usage when in AArch32 state, both A- and M-profile. diff --git a/target/arm/helper.c b/target/arm/helper.c index 6151c77505..c62ed05c12 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11842,6 +11842,20 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env) return arm_mmu_idx_el(env, arm_current_el(env)); } +static inline bool fgt_svc(CPUARMState *env, int el) +{ + /* + * Assuming fine-grained-traps are active, return true if we + * should be trapping on SVC instructions. Only AArch64 can + * trap on an SVC at EL1, but we don't need to special-case this + * because if this is AArch32 EL1 then arm_fgt_active() is false. + * We also know el is 0 or 1. + */ + return el == 0 ? + FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, SVC_EL0) : + FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, SVC_EL1); +} + static CPUARMTBFlags rebuild_hflags_common(CPUARMState *env, int fp_el, ARMMMUIdx mmu_idx, CPUARMTBFlags flags) @@ -11927,6 +11941,9 @@ static CPUARMTBFlags rebuild_hflags_a32(CPUARMState *env, int fp_el, if (arm_fgt_active(env, el)) { DP_TBFLAG_ANY(flags, FGT_ACTIVE, 1); + if (fgt_svc(env, el)) { + DP_TBFLAG_ANY(flags, FGT_SVC, 1); + } } if (env->uncached_cpsr & CPSR_IL) { @@ -12068,6 +12085,9 @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, if (FIELD_EX64(env->cp15.fgt_exec[FGTREG_HFGITR], HFGITR_EL2, ERET)) { DP_TBFLAG_A64(flags, FGT_ERET, 1); } + if (fgt_svc(env, el)) { + DP_TBFLAG_ANY(flags, FGT_SVC, 1); + } } if (cpu_isar_feature(aa64_mte, env_archcpu(env))) { diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 11bfa3f717..bbfadb7c2e 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2179,6 +2179,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) int opc = extract32(insn, 21, 3); int op2_ll = extract32(insn, 0, 5); int imm16 = extract32(insn, 5, 16); + uint32_t syndrome; switch (opc) { case 0: @@ -2189,8 +2190,13 @@ static void disas_exc(DisasContext *s, uint32_t insn) */ switch (op2_ll) { case 1: /* SVC */ + syndrome = syn_aa64_svc(imm16); + if (s->fgt_svc) { + gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2); + break; + } gen_ss_advance(s); - gen_exception_insn(s, 4, EXCP_SWI, syn_aa64_svc(imm16)); + gen_exception_insn(s, 4, EXCP_SWI, syndrome); break; case 2: /* HVC */ if (s->current_el == 0) { @@ -14751,6 +14757,7 @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE); + dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC); dc->fgt_eret = EX_TBFLAG_A64(tb_flags, FGT_ERET); dc->sve_excp_el = EX_TBFLAG_A64(tb_flags, SVEEXC_EL); dc->sme_excp_el = EX_TBFLAG_A64(tb_flags, SMEEXC_EL); diff --git a/target/arm/translate.c b/target/arm/translate.c index 3f51dc6a6b..c23a3462bf 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8834,9 +8834,14 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a) (a->imm == semihost_imm)) { gen_exception_internal_insn(s, EXCP_SEMIHOST); } else { - gen_update_pc(s, curr_insn_len(s)); - s->svc_imm = a->imm; - s->base.is_jmp = DISAS_SWI; + if (s->fgt_svc) { + uint32_t syndrome = syn_aa32_svc(a->imm, s->thumb); + gen_exception_insn_el(s, 0, EXCP_UDEF, syndrome, 2); + } else { + gen_update_pc(s, curr_insn_len(s)); + s->svc_imm = a->imm; + s->base.is_jmp = DISAS_SWI; + } } return true; } @@ -9417,6 +9422,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) dc->align_mem = EX_TBFLAG_ANY(tb_flags, ALIGN_MEM); dc->pstate_il = EX_TBFLAG_ANY(tb_flags, PSTATE__IL); dc->fgt_active = EX_TBFLAG_ANY(tb_flags, FGT_ACTIVE); + dc->fgt_svc = EX_TBFLAG_ANY(tb_flags, FGT_SVC); if (arm_feature(env, ARM_FEATURE_M)) { dc->vfp_enabled = 1; diff --git a/target/arm/translate.h b/target/arm/translate.h index 62a7706eab..3717824b75 100644 --- a/target/arm/translate.h +++ b/target/arm/translate.h @@ -134,6 +134,8 @@ typedef struct DisasContext { bool fgt_active; /* True if fine-grained trap on ERET is enabled */ bool fgt_eret; + /* True if fine-grained trap on SVC is enabled */ + bool fgt_svc; /* * >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI. * < 0, set by the current instruction.