On Sat, 21 Aug 2021 at 21:00, Richard Henderson <richard.hender...@linaro.org> wrote: > > For A64, any input to an indirect branch can cause this. > > For A32, many indirect branch paths force the branch to be aligned, > but BXWritePC does not. This includes the BX instruction but also > other interworking changes to PC. Prior to v8, this case is UNDEFINED. > With v8, this is CONSTRAINED UNPREDICTABLE and may either raise an > exception or force align the PC. > > We choose to raise an exception because we have the infrastructure, > it makes the generated code for gen_bx simpler, and it has the > possibility of catching more guest bugs. > > Signed-off-by: Richard Henderson <richard.hender...@linaro.org> > --- > target/arm/helper.h | 1 + > target/arm/syndrome.h | 5 +++++ > target/arm/tlb_helper.c | 24 +++++++++++++++++++++++ > target/arm/translate-a64.c | 21 ++++++++++++++++++-- > target/arm/translate.c | 39 +++++++++++++++++++++++++++++++------- > 5 files changed, 81 insertions(+), 9 deletions(-) > > diff --git a/target/arm/helper.h b/target/arm/helper.h > index 248569b0cd..d629ee6859 100644 > --- a/target/arm/helper.h > +++ b/target/arm/helper.h > @@ -47,6 +47,7 @@ DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, > DEF_HELPER_2(exception_internal, void, env, i32) > DEF_HELPER_4(exception_with_syndrome, void, env, i32, i32, i32) > DEF_HELPER_2(exception_bkpt_insn, void, env, i32) > +DEF_HELPER_2(exception_pc_alignment, noreturn, env, tl) > DEF_HELPER_1(setend, void, env) > DEF_HELPER_2(wfi, void, env, i32) > DEF_HELPER_1(wfe, void, env) > diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h > index 54d135897b..e9d97fac6e 100644 > --- a/target/arm/syndrome.h > +++ b/target/arm/syndrome.h > @@ -275,4 +275,9 @@ static inline uint32_t syn_illegalstate(void) > return (EC_ILLEGALSTATE << ARM_EL_EC_SHIFT) | ARM_EL_IL; > } > > +static inline uint32_t syn_pcalignment(void) > +{ > + return (EC_PCALIGNMENT << ARM_EL_EC_SHIFT) | ARM_EL_IL; > +} > + > #endif /* TARGET_ARM_SYNDROME_H */ > diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c > index 3107f9823e..25c422976e 100644 > --- a/target/arm/tlb_helper.c > +++ b/target/arm/tlb_helper.c > @@ -9,6 +9,7 @@ > #include "cpu.h" > #include "internals.h" > #include "exec/exec-all.h" > +#include "exec/helper-proto.h" > > static inline uint32_t merge_syn_data_abort(uint32_t template_syn, > unsigned int target_el, > @@ -123,6 +124,29 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr > vaddr, > arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); > } > > +void helper_exception_pc_alignment(CPUARMState *env, target_ulong pc) > +{ > + int target_el = exception_target_el(env); > + > + if (target_el == 2 || arm_el_is_aa64(env, target_el)) { > + /* > + * To aarch64 and aarch32 el2, pc alignment has a > + * special exception class. > + */ > + env->exception.vaddress = pc; > + env->exception.fsr = 0; > + raise_exception(env, EXCP_PREFETCH_ABORT, syn_pcalignment(), > target_el); > + } else { > + /* > + * To aarch32 el1, pc alignment is like data alignment > + * except with a prefetch abort. > + */ > + ARMMMUFaultInfo fi = { .type = ARMFault_Alignment }; > + arm_deliver_fault(env_archcpu(env), pc, MMU_INST_FETCH, > + cpu_mmu_index(env, true), &fi);
I don't think you should need to special case AArch64 vs AArch32 like this; you can do env->exception.vaddress = pc; env->exception.fsr = the_fsr; raise_exception(env, EXCP_PREFETCH_ABORT, syn_pcalignment(), target_el); for both. AArch64/AArch32-Hyp exception entry will ignore exception.fsr, and AArch32-not-Hyp entry will ignore exception.syndrome. We could probably do with factoring out the "if (something) { fsr = arm_fi_to_lfsc(&fi) } else { fsr = arm_fi_to_sfsc(&fi); }" logic which we currently duplicate in arm_deliver_fault() and do_ats_write() and arm_debug_exception_fsr() and also want here. (NB I haven't checked these really are doing exactly the same condition check...) -- PMM