From patchwork Sat Feb 15 16:07:20 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 24709 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-pd0-f197.google.com (mail-pd0-f197.google.com [209.85.192.197]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id CD7E8203BE for ; Sat, 15 Feb 2014 16:08:50 +0000 (UTC) Received: by mail-pd0-f197.google.com with SMTP id x10sf28936071pdj.4 for ; Sat, 15 Feb 2014 08:08:50 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=rSo4c2zTx3128NJ7X5yhCdXjfLk+e89ffHkQpIpLfUQ=; b=X4BHJexGJDaMGsqMeYd9IX2QX05s9z+58VPZWwh244GyryCCOCAto8z7cUutCMRs7H xyaNOcbkNc7jD0v+BIt0BXz1nOdhXB7PY3wa9lzB5ZsQV1nQfD21NmFYOWoYB0Zfcv4i yweINwlZNRNERRDPFSkJdwwVl4oJaOe+m7NebZ9tiCC4jBilQfIKuD7BRB1SctQBAyrw RnQfP+1seQwS2n3yUZC2/sFAP+ye04k5lPdRD3fxFtKWnWnWZua8MlGj6NfMy986oyJ/ YRWlT1bs36h7kKemiHw4x5dVvEcrEdZ4z+rqruEY8R8dWLUYSyRk8zQ3BjvIq+gadluD WJFw== X-Gm-Message-State: ALoCoQlei3lBYG9nYijr7KOs+Rrau4UrD4lw4PEglqcUq48F0w3kwu231eZA+xJIqDttpzddEXew X-Received: by 10.67.14.70 with SMTP id fe6mr5993561pad.15.1392480530036; Sat, 15 Feb 2014 08:08:50 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.85.35 with SMTP id m32ls420152qgd.81.gmail; Sat, 15 Feb 2014 08:08:49 -0800 (PST) X-Received: by 10.220.131.210 with SMTP id y18mr10076834vcs.12.1392480529885; Sat, 15 Feb 2014 08:08:49 -0800 (PST) Received: from mail-ve0-f178.google.com (mail-ve0-f178.google.com [209.85.128.178]) by mx.google.com with ESMTPS id si7si2990919vdc.128.2014.02.15.08.08.49 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 15 Feb 2014 08:08:49 -0800 (PST) Received-SPF: neutral (google.com: 209.85.128.178 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.178; Received: by mail-ve0-f178.google.com with SMTP id oy12so10472328veb.23 for ; Sat, 15 Feb 2014 08:08:49 -0800 (PST) X-Received: by 10.52.27.9 with SMTP id p9mr4832836vdg.28.1392480529791; Sat, 15 Feb 2014 08:08:49 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp25632vcz; Sat, 15 Feb 2014 08:08:48 -0800 (PST) X-Received: by 10.180.72.195 with SMTP id f3mr6388243wiv.61.1392480528223; Sat, 15 Feb 2014 08:08:48 -0800 (PST) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [2001:8b0:1d0::1]) by mx.google.com with ESMTPS id cy3si3869531wib.39.2014.02.15.08.08.46 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Sat, 15 Feb 2014 08:08:48 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::1 as permitted sender) client-ip=2001:8b0:1d0::1; Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1WEhm2-0006gY-35; Sat, 15 Feb 2014 16:07:26 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, Alexander Graf , Michael Matz , Claudio Fontana , Dirk Mueller , Laurent Desnogues , kvmarm@lists.cs.columbia.edu, Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Christoffer Dall , Will Newton , Peter Crosthwaite , Rob Herring Subject: [PATCH v3 27/31] target-arm: Add support for generating exceptions with syndrome information Date: Sat, 15 Feb 2014 16:07:20 +0000 Message-Id: <1392480444-25565-28-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1392480444-25565-1-git-send-email-peter.maydell@linaro.org> References: <1392480444-25565-1-git-send-email-peter.maydell@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.178 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , 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 --- target-arm/cpu.h | 14 ++++++ target-arm/helper.h | 3 +- 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/cpu.h b/target-arm/cpu.h index 3ec752e..bf8b7d5 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -52,6 +52,20 @@ #define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ #define EXCP_STREX 10 +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; +} + #define ARMV7M_EXCP_RESET 1 #define ARMV7M_EXCP_NMI 2 #define ARMV7M_EXCP_HARD 3 diff --git a/target-arm/helper.h b/target-arm/helper.h index 174c615..8986fcd 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/op_helper.c b/target-arm/op_helper.c index fa383b3..0149e2f 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -225,9 +225,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 d42f23f..af43aab 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -170,18 +170,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; } @@ -213,7 +232,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; @@ -222,7 +241,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) \ @@ -1354,6 +1374,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: @@ -1364,7 +1385,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) { @@ -1372,7 +1393,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) { @@ -1521,7 +1542,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, @@ -8901,7 +8922,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; @@ -8964,7 +8985,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 42eb785..30eafc3 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -182,12 +182,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) @@ -899,6 +910,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) { @@ -3912,25 +3950,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) { @@ -7140,7 +7159,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, @@ -7620,6 +7639,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 */ @@ -7628,8 +7649,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: @@ -8636,11 +8658,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; } } @@ -10425,9 +10448,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); @@ -10544,6 +10570,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; } @@ -10579,11 +10606,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 @@ -10703,7 +10730,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; } @@ -10711,7 +10738,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; } @@ -10720,7 +10747,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; @@ -10800,9 +10827,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); } @@ -10812,11 +10839,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, @@ -10845,7 +10872,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 67da699..fa029a0 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;