[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating
From: |
Peter Crosthwaite |
Subject: |
Re: [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information |
Date: |
Mon, 17 Mar 2014 13:19:18 +1000 |
On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <address@hidden> 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 <address@hidden>
> ---
> 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 <address@hidden>
(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
>
>
- [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h, (continued)
- [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h, Peter Maydell, 2014/03/06
- [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor, Peter Maydell, 2014/03/06
- [Qemu-devel] [PATCH v4 03/21] target-arm: Define exception record for AArch64 exceptions, Peter Maydell, 2014/03/06
- [Qemu-devel] [PATCH v4 15/21] target-arm: Add AArch64 ELR_EL1 register., Peter Maydell, 2014/03/06
- [Qemu-devel] [PATCH v4 02/21] target-arm: Implement AArch64 DAIF system register, Peter Maydell, 2014/03/06
- [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information, Peter Maydell, 2014/03/06
- Re: [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information,
Peter Crosthwaite <=
- [Qemu-devel] [PATCH v4 07/21] target-arm: A64: Correctly fault FP/Neon if CPACR.FPEN set, Peter Maydell, 2014/03/06
- [Qemu-devel] [PATCH v4 13/21] target-arm: Use dedicated CPU state fields for ARM946 access bit registers, Peter Maydell, 2014/03/06
- [Qemu-devel] [PATCH v4 08/21] target-arm: A64: Add assertion that FP access was checked, Peter Maydell, 2014/03/06
- Re: [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!), Xuebing Wang, 2014/03/06