Message ID | 1394134385-1727-6-git-send-email-peter.maydell@linaro.org |
---|---|
State | Superseded |
Headers | show |
On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote: > Add new helpers exception_with_syndrome (for generating an exception > with syndrome information) and exception_uncategorized (for generating > an exception with "Unknown or Uncategorized Reason", which have a syndrome > register value of zero), and use them to generate the correct syndrome > information for exceptions which are raised directly from generated code. > > This patch includes moving the A32/T32 gen_exception_insn functions > further up in the source file; they will be needed for "VFP/Neon disabled" > exception generation later. > > Signed-off-by: Peter Maydell <peter.maydell@linaro.org> > --- > target-arm/helper.h | 3 +- > target-arm/internals.h | 14 ++++++ > target-arm/op_helper.c | 19 ++++++++- > target-arm/translate-a64.c | 49 +++++++++++++++------ > target-arm/translate.c | 103 ++++++++++++++++++++++++++++----------------- > target-arm/translate.h | 4 ++ > 6 files changed, 138 insertions(+), 54 deletions(-) > > diff --git a/target-arm/helper.h b/target-arm/helper.h > index 7f23cb8..2729ea5 100644 > --- a/target-arm/helper.h > +++ b/target-arm/helper.h > @@ -48,7 +48,8 @@ DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32) > > DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, > i32, i32, i32, i32) > -DEF_HELPER_2(exception, void, env, i32) > +DEF_HELPER_2(exception_internal, void, env, i32) > +DEF_HELPER_3(exception_with_syndrome, void, env, i32, i32) > DEF_HELPER_1(wfi, void, env) > > DEF_HELPER_3(cpsr_write, void, env, i32, i32) > diff --git a/target-arm/internals.h b/target-arm/internals.h > index 2c0db20..9bec4e1 100644 > --- a/target-arm/internals.h > +++ b/target-arm/internals.h > @@ -25,6 +25,20 @@ > #ifndef TARGET_ARM_INTERNALS_H > #define TARGET_ARM_INTERNALS_H > > +static inline bool excp_is_internal(int excp) > +{ > + /* Return true if this exception number represents a QEMU-internal > + * exception that will not be passed to the guest. > + */ > + return excp == EXCP_INTERRUPT > + || excp == EXCP_HLT > + || excp == EXCP_DEBUG > + || excp == EXCP_HALTED > + || excp == EXCP_EXCEPTION_EXIT > + || excp == EXCP_KERNEL_TRAP > + || excp == EXCP_STREX; > +} > + > /* Scale factor for generic timers, ie number of ns per tick. > * This gives a 62.5MHz timer. > */ > diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c > index bef2cf6..b1db672 100644 > --- a/target-arm/op_helper.c > +++ b/target-arm/op_helper.c > @@ -226,9 +226,26 @@ void HELPER(wfi)(CPUARMState *env) > cpu_loop_exit(env); > } > > -void HELPER(exception)(CPUARMState *env, uint32_t excp) > +/* Raise an internal-to-QEMU exception. This is limited to only > + * those EXCP values which are special cases for QEMU to interrupt > + * execution and not to be used for exceptions which are passed to > + * the guest (those must all have syndrome information and thus should > + * use exception_with_syndrome). > + */ > +void HELPER(exception_internal)(CPUARMState *env, uint32_t excp) > +{ > + assert(excp_is_internal(excp)); > + env->exception_index = excp; > + cpu_loop_exit(env); > +} > + > +/* Raise an exception with the specified syndrome register value */ > +void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp, > + uint32_t syndrome) > { > + assert(!excp_is_internal(excp)); > env->exception_index = excp; > + env->exception.syndrome = syndrome; > cpu_loop_exit(env); > } > > diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c > index a4f9258..b32068e 100644 > --- a/target-arm/translate-a64.c > +++ b/target-arm/translate-a64.c > @@ -173,18 +173,37 @@ void gen_a64_set_pc_im(uint64_t val) > tcg_gen_movi_i64(cpu_pc, val); > } > > -static void gen_exception(int excp) > +static void gen_exception_internal(int excp) > { > - TCGv_i32 tmp = tcg_temp_new_i32(); > - tcg_gen_movi_i32(tmp, excp); > - gen_helper_exception(cpu_env, tmp); > - tcg_temp_free_i32(tmp); > + TCGv_i32 tcg_excp = tcg_const_i32(excp); > + > + assert(excp_is_internal(excp)); > + gen_helper_exception_internal(cpu_env, tcg_excp); > + tcg_temp_free_i32(tcg_excp); > +} > + > +static void gen_exception(int excp, uint32_t syndrome) > +{ > + TCGv_i32 tcg_excp = tcg_const_i32(excp); > + TCGv_i32 tcg_syn = tcg_const_i32(syndrome); > + > + gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn); > + tcg_temp_free_i32(tcg_syn); > + tcg_temp_free_i32(tcg_excp); > +} > + > +static void gen_exception_internal_insn(DisasContext *s, int offset, int excp) > +{ > + gen_a64_set_pc_im(s->pc - offset); > + gen_exception_internal(excp); > + s->is_jmp = DISAS_EXC; > } > > -static void gen_exception_insn(DisasContext *s, int offset, int excp) > +static void gen_exception_insn(DisasContext *s, int offset, int excp, > + uint32_t syndrome) > { > gen_a64_set_pc_im(s->pc - offset); > - gen_exception(excp); > + gen_exception(excp, syndrome); > s->is_jmp = DISAS_EXC; > } > > @@ -216,7 +235,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) > } else { > gen_a64_set_pc_im(dest); > if (s->singlestep_enabled) { > - gen_exception(EXCP_DEBUG); > + gen_exception_internal(EXCP_DEBUG); > } > tcg_gen_exit_tb(0); > s->is_jmp = DISAS_JUMP; > @@ -225,7 +244,8 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) > > static void unallocated_encoding(DisasContext *s) > { > - gen_exception_insn(s, 4, EXCP_UDEF); > + /* Unallocated and reserved encodings are uncategorized */ > + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); > } > > #define unsupported_encoding(s, insn) \ > @@ -1370,6 +1390,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); > > switch (opc) { > case 0: > @@ -1380,7 +1401,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) > unallocated_encoding(s); > break; > } > - gen_exception_insn(s, 0, EXCP_SWI); > + gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); > break; > case 1: > if (op2_ll != 0) { > @@ -1388,7 +1409,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) > break; > } > /* BRK */ > - gen_exception_insn(s, 0, EXCP_BKPT); > + gen_exception_insn(s, 0, EXCP_BKPT, syn_aa64_bkpt(imm16)); > break; > case 2: > if (op2_ll != 0) { > @@ -1537,7 +1558,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, > tcg_gen_mov_i64(cpu_exclusive_test, addr); > tcg_gen_movi_i32(cpu_exclusive_info, > size | is_pair << 2 | (rd << 4) | (rt << 9) | (rt2 << 14)); > - gen_exception_insn(s, 4, EXCP_STREX); > + gen_exception_internal_insn(s, 4, EXCP_STREX); > } > #else > static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, > @@ -9108,7 +9129,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, > if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { > QTAILQ_FOREACH(bp, &env->breakpoints, entry) { > if (bp->pc == dc->pc) { > - gen_exception_insn(dc, 0, EXCP_DEBUG); > + gen_exception_internal_insn(dc, 0, EXCP_DEBUG); > /* Advance PC so that clearing the breakpoint will > invalidate this TB. */ > dc->pc += 2; > @@ -9171,7 +9192,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, > if (dc->is_jmp != DISAS_JUMP) { > gen_a64_set_pc_im(dc->pc); > } > - gen_exception(EXCP_DEBUG); > + gen_exception_internal(EXCP_DEBUG); > } else { > switch (dc->is_jmp) { > case DISAS_NEXT: > diff --git a/target-arm/translate.c b/target-arm/translate.c > index 9a81222..094be07 100644 > --- a/target-arm/translate.c > +++ b/target-arm/translate.c > @@ -183,12 +183,23 @@ static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask) > /* Set NZCV flags from the high 4 bits of var. */ > #define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) > > -static void gen_exception(int excp) > +static void gen_exception_internal(int excp) > { > - TCGv_i32 tmp = tcg_temp_new_i32(); > - tcg_gen_movi_i32(tmp, excp); > - gen_helper_exception(cpu_env, tmp); > - tcg_temp_free_i32(tmp); > + TCGv_i32 tcg_excp = tcg_const_i32(excp); > + > + assert(excp_is_internal(excp)); > + gen_helper_exception_internal(cpu_env, tcg_excp); > + tcg_temp_free_i32(tcg_excp); > +} > + AFAICT this is identical to gen_exception_internal in translate-a64.c. Can they be de-static'd and prototyped in internals.h? > +static void gen_exception(int excp, uint32_t syndrome) > +{ > + TCGv_i32 tcg_excp = tcg_const_i32(excp); > + TCGv_i32 tcg_syn = tcg_const_i32(syndrome); > + > + gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn); > + tcg_temp_free_i32(tcg_syn); > + tcg_temp_free_i32(tcg_excp); > } > And here. Otherwise Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com> (I haven't gone line-line checking all arguments against TRM, but the schema and framework is good). Regards, Peter > static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b) > @@ -900,6 +911,33 @@ static inline void gen_set_pc_im(DisasContext *s, target_ulong val) > tcg_gen_movi_i32(cpu_R[15], val); > } > > +static inline void > +gen_set_condexec (DisasContext *s) > +{ > + if (s->condexec_mask) { > + uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); > + TCGv_i32 tmp = tcg_temp_new_i32(); > + tcg_gen_movi_i32(tmp, val); > + store_cpu_field(tmp, condexec_bits); > + } > +} > + > +static void gen_exception_internal_insn(DisasContext *s, int offset, int excp) > +{ > + gen_set_condexec(s); > + gen_set_pc_im(s, s->pc - offset); > + gen_exception_internal(excp); > + s->is_jmp = DISAS_JUMP; > +} > + > +static void gen_exception_insn(DisasContext *s, int offset, int excp, int syn) > +{ > + gen_set_condexec(s); > + gen_set_pc_im(s, s->pc - offset); > + gen_exception(excp, syn); > + s->is_jmp = DISAS_JUMP; > +} > + > /* Force a TB lookup after an instruction that changes the CPU state. */ > static inline void gen_lookup_tb(DisasContext *s) > { > @@ -3913,25 +3951,6 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr) > s->is_jmp = DISAS_UPDATE; > } > > -static inline void > -gen_set_condexec (DisasContext *s) > -{ > - if (s->condexec_mask) { > - uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); > - TCGv_i32 tmp = tcg_temp_new_i32(); > - tcg_gen_movi_i32(tmp, val); > - store_cpu_field(tmp, condexec_bits); > - } > -} > - > -static void gen_exception_insn(DisasContext *s, int offset, int excp) > -{ > - gen_set_condexec(s); > - gen_set_pc_im(s, s->pc - offset); > - gen_exception(excp); > - s->is_jmp = DISAS_JUMP; > -} > - > static void gen_nop_hint(DisasContext *s, int val) > { > switch (val) { > @@ -7141,7 +7160,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, > tcg_gen_extu_i32_i64(cpu_exclusive_test, addr); > tcg_gen_movi_i32(cpu_exclusive_info, > size | (rd << 4) | (rt << 8) | (rt2 << 12)); > - gen_exception_insn(s, 4, EXCP_STREX); > + gen_exception_internal_insn(s, 4, EXCP_STREX); > } > #else > static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, > @@ -7651,6 +7670,8 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) > store_reg(s, rd, tmp); > break; > case 7: > + { > + int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4); > /* SMC instruction (op1 == 3) > and undefined instructions (op1 == 0 || op1 == 2) > will trap */ > @@ -7659,8 +7680,9 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) > } > /* bkpt */ > ARCH(5); > - gen_exception_insn(s, 4, EXCP_BKPT); > + gen_exception_insn(s, 4, EXCP_BKPT, syn_aa32_bkpt(imm16, false)); > break; > + } > case 0x8: /* signed multiply */ > case 0xa: > case 0xc: > @@ -8667,11 +8689,12 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) > case 0xf: > /* swi */ > gen_set_pc_im(s, s->pc); > + s->svc_imm = extract32(insn, 0, 24); > s->is_jmp = DISAS_SWI; > break; > default: > illegal_op: > - gen_exception_insn(s, 4, EXCP_UDEF); > + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); > break; > } > } > @@ -10482,9 +10505,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) > break; > > case 0xe: /* bkpt */ > + { > + int imm8 = extract32(insn, 0, 8); > ARCH(5); > - gen_exception_insn(s, 2, EXCP_BKPT); > + gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true)); > break; > + } > > case 0xa: /* rev */ > ARCH(6); > @@ -10601,6 +10627,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) > if (cond == 0xf) { > /* swi */ > gen_set_pc_im(s, s->pc); > + s->svc_imm = extract32(insn, 0, 8); > s->is_jmp = DISAS_SWI; > break; > } > @@ -10636,11 +10663,11 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) > } > return; > undef32: > - gen_exception_insn(s, 4, EXCP_UDEF); > + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); > return; > illegal_op: > undef: > - gen_exception_insn(s, 2, EXCP_UDEF); > + gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized()); > } > > /* generate intermediate code in gen_opc_buf and gen_opparam_buf for > @@ -10761,7 +10788,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, > if (dc->pc >= 0xffff0000) { > /* We always get here via a jump, so know we are not in a > conditional execution block. */ > - gen_exception(EXCP_KERNEL_TRAP); > + gen_exception_internal(EXCP_KERNEL_TRAP); > dc->is_jmp = DISAS_UPDATE; > break; > } > @@ -10769,7 +10796,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, > if (dc->pc >= 0xfffffff0 && IS_M(env)) { > /* We always get here via a jump, so know we are not in a > conditional execution block. */ > - gen_exception(EXCP_EXCEPTION_EXIT); > + gen_exception_internal(EXCP_EXCEPTION_EXIT); > dc->is_jmp = DISAS_UPDATE; > break; > } > @@ -10778,7 +10805,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, > if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { > QTAILQ_FOREACH(bp, &env->breakpoints, entry) { > if (bp->pc == dc->pc) { > - gen_exception_insn(dc, 0, EXCP_DEBUG); > + gen_exception_internal_insn(dc, 0, EXCP_DEBUG); > /* Advance PC so that clearing the breakpoint will > invalidate this TB. */ > dc->pc += 2; > @@ -10858,9 +10885,9 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, > if (dc->condjmp) { > gen_set_condexec(dc); > if (dc->is_jmp == DISAS_SWI) { > - gen_exception(EXCP_SWI); > + gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); > } else { > - gen_exception(EXCP_DEBUG); > + gen_exception_internal(EXCP_DEBUG); > } > gen_set_label(dc->condlabel); > } > @@ -10870,11 +10897,11 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, > } > gen_set_condexec(dc); > if (dc->is_jmp == DISAS_SWI && !dc->condjmp) { > - gen_exception(EXCP_SWI); > + gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); > } else { > /* FIXME: Single stepping a WFI insn will not halt > the CPU. */ > - gen_exception(EXCP_DEBUG); > + gen_exception_internal(EXCP_DEBUG); > } > } else { > /* While branches must always occur at the end of an IT block, > @@ -10903,7 +10930,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, > gen_helper_wfi(cpu_env); > break; > case DISAS_SWI: > - gen_exception(EXCP_SWI); > + gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); > break; > } > if (dc->condjmp) { > diff --git a/target-arm/translate.h b/target-arm/translate.h > index 889a031..4d3d363 100644 > --- a/target-arm/translate.h > +++ b/target-arm/translate.h > @@ -23,6 +23,10 @@ typedef struct DisasContext { > int vfp_enabled; > int vec_len; > int vec_stride; > + /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI > + * so that top level loop can generate correct syndrome information. > + */ > + uint32_t svc_imm; > int aarch64; > int current_pl; > GHashTable *cp_regs; > -- > 1.9.0 > >
On 17 March 2014 03:19, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote: > On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote: >> -static void gen_exception(int excp) >> +static void gen_exception_internal(int excp) >> { >> - TCGv_i32 tmp = tcg_temp_new_i32(); >> - tcg_gen_movi_i32(tmp, excp); >> - gen_helper_exception(cpu_env, tmp); >> - tcg_temp_free_i32(tmp); >> + TCGv_i32 tcg_excp = tcg_const_i32(excp); >> + >> + assert(excp_is_internal(excp)); >> + gen_helper_exception_internal(cpu_env, tcg_excp); >> + tcg_temp_free_i32(tcg_excp); >> +} >> + > > AFAICT this is identical to gen_exception_internal in translate-a64.c. > Can they be de-static'd and prototyped in internals.h? This is true, but it would break the current situation we have where translate.c and translate-a64.c are entirely independent and you never have to worry about breaking one if you make changes to the other, which is why I didn't do it. Maybe that's not very important, but it didn't seem worth going against for the sake of a couple of helpers just a few lines long. (If we do make them common then translate.h would be the right place for the prototypes.) thanks -- PMM
diff --git a/target-arm/helper.h b/target-arm/helper.h index 7f23cb8..2729ea5 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -48,7 +48,8 @@ DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_2(exception, void, env, i32) +DEF_HELPER_2(exception_internal, void, env, i32) +DEF_HELPER_3(exception_with_syndrome, void, env, i32, i32) DEF_HELPER_1(wfi, void, env) DEF_HELPER_3(cpsr_write, void, env, i32, i32) diff --git a/target-arm/internals.h b/target-arm/internals.h index 2c0db20..9bec4e1 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -25,6 +25,20 @@ #ifndef TARGET_ARM_INTERNALS_H #define TARGET_ARM_INTERNALS_H +static inline bool excp_is_internal(int excp) +{ + /* Return true if this exception number represents a QEMU-internal + * exception that will not be passed to the guest. + */ + return excp == EXCP_INTERRUPT + || excp == EXCP_HLT + || excp == EXCP_DEBUG + || excp == EXCP_HALTED + || excp == EXCP_EXCEPTION_EXIT + || excp == EXCP_KERNEL_TRAP + || excp == EXCP_STREX; +} + /* Scale factor for generic timers, ie number of ns per tick. * This gives a 62.5MHz timer. */ diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index bef2cf6..b1db672 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -226,9 +226,26 @@ void HELPER(wfi)(CPUARMState *env) cpu_loop_exit(env); } -void HELPER(exception)(CPUARMState *env, uint32_t excp) +/* Raise an internal-to-QEMU exception. This is limited to only + * those EXCP values which are special cases for QEMU to interrupt + * execution and not to be used for exceptions which are passed to + * the guest (those must all have syndrome information and thus should + * use exception_with_syndrome). + */ +void HELPER(exception_internal)(CPUARMState *env, uint32_t excp) +{ + assert(excp_is_internal(excp)); + env->exception_index = excp; + cpu_loop_exit(env); +} + +/* Raise an exception with the specified syndrome register value */ +void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp, + uint32_t syndrome) { + assert(!excp_is_internal(excp)); env->exception_index = excp; + env->exception.syndrome = syndrome; cpu_loop_exit(env); } diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index a4f9258..b32068e 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -173,18 +173,37 @@ void gen_a64_set_pc_im(uint64_t val) tcg_gen_movi_i64(cpu_pc, val); } -static void gen_exception(int excp) +static void gen_exception_internal(int excp) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, excp); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); + TCGv_i32 tcg_excp = tcg_const_i32(excp); + + assert(excp_is_internal(excp)); + gen_helper_exception_internal(cpu_env, tcg_excp); + tcg_temp_free_i32(tcg_excp); +} + +static void gen_exception(int excp, uint32_t syndrome) +{ + TCGv_i32 tcg_excp = tcg_const_i32(excp); + TCGv_i32 tcg_syn = tcg_const_i32(syndrome); + + gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn); + tcg_temp_free_i32(tcg_syn); + tcg_temp_free_i32(tcg_excp); +} + +static void gen_exception_internal_insn(DisasContext *s, int offset, int excp) +{ + gen_a64_set_pc_im(s->pc - offset); + gen_exception_internal(excp); + s->is_jmp = DISAS_EXC; } -static void gen_exception_insn(DisasContext *s, int offset, int excp) +static void gen_exception_insn(DisasContext *s, int offset, int excp, + uint32_t syndrome) { gen_a64_set_pc_im(s->pc - offset); - gen_exception(excp); + gen_exception(excp, syndrome); s->is_jmp = DISAS_EXC; } @@ -216,7 +235,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) } else { gen_a64_set_pc_im(dest); if (s->singlestep_enabled) { - gen_exception(EXCP_DEBUG); + gen_exception_internal(EXCP_DEBUG); } tcg_gen_exit_tb(0); s->is_jmp = DISAS_JUMP; @@ -225,7 +244,8 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) static void unallocated_encoding(DisasContext *s) { - gen_exception_insn(s, 4, EXCP_UDEF); + /* Unallocated and reserved encodings are uncategorized */ + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); } #define unsupported_encoding(s, insn) \ @@ -1370,6 +1390,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); switch (opc) { case 0: @@ -1380,7 +1401,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) unallocated_encoding(s); break; } - gen_exception_insn(s, 0, EXCP_SWI); + gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); break; case 1: if (op2_ll != 0) { @@ -1388,7 +1409,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) break; } /* BRK */ - gen_exception_insn(s, 0, EXCP_BKPT); + gen_exception_insn(s, 0, EXCP_BKPT, syn_aa64_bkpt(imm16)); break; case 2: if (op2_ll != 0) { @@ -1537,7 +1558,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, tcg_gen_mov_i64(cpu_exclusive_test, addr); tcg_gen_movi_i32(cpu_exclusive_info, size | is_pair << 2 | (rd << 4) | (rt << 9) | (rt2 << 14)); - gen_exception_insn(s, 4, EXCP_STREX); + gen_exception_internal_insn(s, 4, EXCP_STREX); } #else static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, @@ -9108,7 +9129,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { if (bp->pc == dc->pc) { - gen_exception_insn(dc, 0, EXCP_DEBUG); + gen_exception_internal_insn(dc, 0, EXCP_DEBUG); /* Advance PC so that clearing the breakpoint will invalidate this TB. */ dc->pc += 2; @@ -9171,7 +9192,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, if (dc->is_jmp != DISAS_JUMP) { gen_a64_set_pc_im(dc->pc); } - gen_exception(EXCP_DEBUG); + gen_exception_internal(EXCP_DEBUG); } else { switch (dc->is_jmp) { case DISAS_NEXT: diff --git a/target-arm/translate.c b/target-arm/translate.c index 9a81222..094be07 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -183,12 +183,23 @@ static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask) /* Set NZCV flags from the high 4 bits of var. */ #define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV) -static void gen_exception(int excp) +static void gen_exception_internal(int excp) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, excp); - gen_helper_exception(cpu_env, tmp); - tcg_temp_free_i32(tmp); + TCGv_i32 tcg_excp = tcg_const_i32(excp); + + assert(excp_is_internal(excp)); + gen_helper_exception_internal(cpu_env, tcg_excp); + tcg_temp_free_i32(tcg_excp); +} + +static void gen_exception(int excp, uint32_t syndrome) +{ + TCGv_i32 tcg_excp = tcg_const_i32(excp); + TCGv_i32 tcg_syn = tcg_const_i32(syndrome); + + gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn); + tcg_temp_free_i32(tcg_syn); + tcg_temp_free_i32(tcg_excp); } static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b) @@ -900,6 +911,33 @@ static inline void gen_set_pc_im(DisasContext *s, target_ulong val) tcg_gen_movi_i32(cpu_R[15], val); } +static inline void +gen_set_condexec (DisasContext *s) +{ + if (s->condexec_mask) { + uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); + TCGv_i32 tmp = tcg_temp_new_i32(); + tcg_gen_movi_i32(tmp, val); + store_cpu_field(tmp, condexec_bits); + } +} + +static void gen_exception_internal_insn(DisasContext *s, int offset, int excp) +{ + gen_set_condexec(s); + gen_set_pc_im(s, s->pc - offset); + gen_exception_internal(excp); + s->is_jmp = DISAS_JUMP; +} + +static void gen_exception_insn(DisasContext *s, int offset, int excp, int syn) +{ + gen_set_condexec(s); + gen_set_pc_im(s, s->pc - offset); + gen_exception(excp, syn); + s->is_jmp = DISAS_JUMP; +} + /* Force a TB lookup after an instruction that changes the CPU state. */ static inline void gen_lookup_tb(DisasContext *s) { @@ -3913,25 +3951,6 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr) s->is_jmp = DISAS_UPDATE; } -static inline void -gen_set_condexec (DisasContext *s) -{ - if (s->condexec_mask) { - uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1); - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, val); - store_cpu_field(tmp, condexec_bits); - } -} - -static void gen_exception_insn(DisasContext *s, int offset, int excp) -{ - gen_set_condexec(s); - gen_set_pc_im(s, s->pc - offset); - gen_exception(excp); - s->is_jmp = DISAS_JUMP; -} - static void gen_nop_hint(DisasContext *s, int val) { switch (val) { @@ -7141,7 +7160,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, tcg_gen_extu_i32_i64(cpu_exclusive_test, addr); tcg_gen_movi_i32(cpu_exclusive_info, size | (rd << 4) | (rt << 8) | (rt2 << 12)); - gen_exception_insn(s, 4, EXCP_STREX); + gen_exception_internal_insn(s, 4, EXCP_STREX); } #else static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2, @@ -7651,6 +7670,8 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) store_reg(s, rd, tmp); break; case 7: + { + int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4); /* SMC instruction (op1 == 3) and undefined instructions (op1 == 0 || op1 == 2) will trap */ @@ -7659,8 +7680,9 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) } /* bkpt */ ARCH(5); - gen_exception_insn(s, 4, EXCP_BKPT); + gen_exception_insn(s, 4, EXCP_BKPT, syn_aa32_bkpt(imm16, false)); break; + } case 0x8: /* signed multiply */ case 0xa: case 0xc: @@ -8667,11 +8689,12 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) case 0xf: /* swi */ gen_set_pc_im(s, s->pc); + s->svc_imm = extract32(insn, 0, 24); s->is_jmp = DISAS_SWI; break; default: illegal_op: - gen_exception_insn(s, 4, EXCP_UDEF); + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); break; } } @@ -10482,9 +10505,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) break; case 0xe: /* bkpt */ + { + int imm8 = extract32(insn, 0, 8); ARCH(5); - gen_exception_insn(s, 2, EXCP_BKPT); + gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true)); break; + } case 0xa: /* rev */ ARCH(6); @@ -10601,6 +10627,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) if (cond == 0xf) { /* swi */ gen_set_pc_im(s, s->pc); + s->svc_imm = extract32(insn, 0, 8); s->is_jmp = DISAS_SWI; break; } @@ -10636,11 +10663,11 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) } return; undef32: - gen_exception_insn(s, 4, EXCP_UDEF); + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); return; illegal_op: undef: - gen_exception_insn(s, 2, EXCP_UDEF); + gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized()); } /* generate intermediate code in gen_opc_buf and gen_opparam_buf for @@ -10761,7 +10788,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, if (dc->pc >= 0xffff0000) { /* We always get here via a jump, so know we are not in a conditional execution block. */ - gen_exception(EXCP_KERNEL_TRAP); + gen_exception_internal(EXCP_KERNEL_TRAP); dc->is_jmp = DISAS_UPDATE; break; } @@ -10769,7 +10796,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, if (dc->pc >= 0xfffffff0 && IS_M(env)) { /* We always get here via a jump, so know we are not in a conditional execution block. */ - gen_exception(EXCP_EXCEPTION_EXIT); + gen_exception_internal(EXCP_EXCEPTION_EXIT); dc->is_jmp = DISAS_UPDATE; break; } @@ -10778,7 +10805,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) { QTAILQ_FOREACH(bp, &env->breakpoints, entry) { if (bp->pc == dc->pc) { - gen_exception_insn(dc, 0, EXCP_DEBUG); + gen_exception_internal_insn(dc, 0, EXCP_DEBUG); /* Advance PC so that clearing the breakpoint will invalidate this TB. */ dc->pc += 2; @@ -10858,9 +10885,9 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, if (dc->condjmp) { gen_set_condexec(dc); if (dc->is_jmp == DISAS_SWI) { - gen_exception(EXCP_SWI); + gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); } else { - gen_exception(EXCP_DEBUG); + gen_exception_internal(EXCP_DEBUG); } gen_set_label(dc->condlabel); } @@ -10870,11 +10897,11 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, } gen_set_condexec(dc); if (dc->is_jmp == DISAS_SWI && !dc->condjmp) { - gen_exception(EXCP_SWI); + gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); } else { /* FIXME: Single stepping a WFI insn will not halt the CPU. */ - gen_exception(EXCP_DEBUG); + gen_exception_internal(EXCP_DEBUG); } } else { /* While branches must always occur at the end of an IT block, @@ -10903,7 +10930,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, gen_helper_wfi(cpu_env); break; case DISAS_SWI: - gen_exception(EXCP_SWI); + gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); break; } if (dc->condjmp) { diff --git a/target-arm/translate.h b/target-arm/translate.h index 889a031..4d3d363 100644 --- a/target-arm/translate.h +++ b/target-arm/translate.h @@ -23,6 +23,10 @@ typedef struct DisasContext { int vfp_enabled; int vec_len; int vec_stride; + /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI + * so that top level loop can generate correct syndrome information. + */ + uint32_t svc_imm; int aarch64; int current_pl; GHashTable *cp_regs;
Add new helpers exception_with_syndrome (for generating an exception with syndrome information) and exception_uncategorized (for generating an exception with "Unknown or Uncategorized Reason", which have a syndrome register value of zero), and use them to generate the correct syndrome information for exceptions which are raised directly from generated code. This patch includes moving the A32/T32 gen_exception_insn functions further up in the source file; they will be needed for "VFP/Neon disabled" exception generation later. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target-arm/helper.h | 3 +- target-arm/internals.h | 14 ++++++ target-arm/op_helper.c | 19 ++++++++- target-arm/translate-a64.c | 49 +++++++++++++++------ target-arm/translate.c | 103 ++++++++++++++++++++++++++++----------------- target-arm/translate.h | 4 ++ 6 files changed, 138 insertions(+), 54 deletions(-)