diff --git a/qemu/target-arm/cpu.h b/qemu/target-arm/cpu.h index 7c107903..f3d14b5c 100644 --- a/qemu/target-arm/cpu.h +++ b/qemu/target-arm/cpu.h @@ -401,6 +401,7 @@ typedef struct CPUARMState { uint32_t syndrome; /* AArch64 format syndrome register */ uint32_t fsr; /* AArch32 format fault status register info */ uint64_t vaddress; /* virtual addr associated with exception, if any */ + uint32_t target_el; /* EL the exception should be targeted for */ /* If we implement EL2 we will also need to store information * about the intermediate physical address for stage 2 faults. */ diff --git a/qemu/target-arm/helper.h b/qemu/target-arm/helper.h index 6427c18c..7c1644ec 100644 --- a/qemu/target-arm/helper.h +++ b/qemu/target-arm/helper.h @@ -50,7 +50,7 @@ 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_internal, void, env, i32) -DEF_HELPER_3(exception_with_syndrome, void, env, i32, i32) +DEF_HELPER_4(exception_with_syndrome, void, env, i32, i32, i32) DEF_HELPER_1(wfi, void, env) DEF_HELPER_1(wfe, void, env) DEF_HELPER_1(pre_hvc, void, env) diff --git a/qemu/target-arm/op_helper.c b/qemu/target-arm/op_helper.c index 9a5ce4bb..a51393a5 100644 --- a/qemu/target-arm/op_helper.c +++ b/qemu/target-arm/op_helper.c @@ -246,13 +246,14 @@ void HELPER(exception_internal)(CPUARMState *env, uint32_t excp) /* Raise an exception with the specified syndrome register value */ void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp, - uint32_t syndrome) + uint32_t syndrome, uint32_t target_el) { CPUState *cs = CPU(arm_env_get_cpu(env)); assert(!excp_is_internal(excp)); cs->exception_index = excp; // qq env->exception.syndrome = syndrome; + env->exception.target_el = target_el; cpu_loop_exit(cs); } diff --git a/qemu/target-arm/translate-a64.c b/qemu/target-arm/translate-a64.c index 2992bb5d..99349044 100644 --- a/qemu/target-arm/translate-a64.c +++ b/qemu/target-arm/translate-a64.c @@ -214,13 +214,16 @@ static void gen_exception_internal(DisasContext *s, int excp) tcg_temp_free_i32(tcg_ctx, tcg_excp); } -static void gen_exception(DisasContext *s, int excp, uint32_t syndrome) +static void gen_exception(DisasContext *s, int excp, uint32_t syndrome, uint32_t target_el) { TCGContext *tcg_ctx = s->uc->tcg_ctx; TCGv_i32 tcg_excp = tcg_const_i32(tcg_ctx, excp); TCGv_i32 tcg_syn = tcg_const_i32(tcg_ctx, syndrome); + TCGv_i32 tcg_el = tcg_const_i32(tcg_ctx, target_el); - gen_helper_exception_with_syndrome(tcg_ctx, tcg_ctx->cpu_env, tcg_excp, tcg_syn); + gen_helper_exception_with_syndrome(tcg_ctx, tcg_ctx->cpu_env, tcg_excp, + tcg_syn, tcg_el); + tcg_temp_free_i32(tcg_ctx, tcg_el); tcg_temp_free_i32(tcg_ctx, tcg_syn); tcg_temp_free_i32(tcg_ctx, tcg_excp); } @@ -233,10 +236,10 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp) } static void gen_exception_insn(DisasContext *s, int offset, int excp, - uint32_t syndrome) + uint32_t syndrome, uint32_t target_el) { gen_a64_set_pc_im(s, s->pc - offset); - gen_exception(s, excp, syndrome); + gen_exception(s, excp, syndrome, target_el); s->is_jmp = DISAS_EXC; } @@ -264,7 +267,8 @@ static void gen_step_complete_exception(DisasContext *s) * of the exception, and our syndrome information is always correct. */ gen_ss_advance(s); - gen_exception(s, EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex)); + gen_exception(s, EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex), + default_exception_el(s)); s->is_jmp = DISAS_EXC; } @@ -312,7 +316,8 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest) static void unallocated_encoding(DisasContext *s) { /* Unallocated and reserved encodings are uncategorized */ - gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), + default_exception_el(s)); } #define unsupported_encoding(s, insn) \ @@ -1002,7 +1007,8 @@ static inline bool fp_access_check(DisasContext *s) return true; } - gen_exception_insn(s, 4, EXCP_UDEF, syn_fp_access_trap(1, 0xe, false)); + gen_exception_insn(s, 4, EXCP_UDEF, syn_fp_access_trap(1, 0xe, false), + default_exception_el(s)); return false; } @@ -1529,7 +1535,8 @@ static void disas_exc(DisasContext *s, uint32_t insn) switch (op2_ll) { case 1: gen_ss_advance(s); - gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); + gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16), + default_exception_el(s)); break; case 2: if (s->current_el == 0) { @@ -1542,7 +1549,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) gen_a64_set_pc_im(s, s->pc - 4); gen_helper_pre_hvc(tcg_ctx, tcg_ctx->cpu_env); gen_ss_advance(s); - gen_exception_insn(s, 0, EXCP_HVC, syn_aa64_hvc(imm16)); + gen_exception_insn(s, 0, EXCP_HVC, syn_aa64_hvc(imm16), 2); break; case 3: if (s->current_el == 0) { @@ -1554,7 +1561,7 @@ static void disas_exc(DisasContext *s, uint32_t insn) gen_helper_pre_smc(tcg_ctx, tcg_ctx->cpu_env, tmp); tcg_temp_free_i32(tcg_ctx, tmp); gen_ss_advance(s); - gen_exception_insn(s, 0, EXCP_SMC, syn_aa64_smc(imm16)); + gen_exception_insn(s, 0, EXCP_SMC, syn_aa64_smc(imm16), 3); break; default: unallocated_encoding(s); @@ -1567,7 +1574,8 @@ static void disas_exc(DisasContext *s, uint32_t insn) break; } /* BRK */ - gen_exception_insn(s, 4, EXCP_BKPT, syn_aa64_bkpt(imm16)); + gen_exception_insn(s, 4, EXCP_BKPT, syn_aa64_bkpt(imm16), + default_exception_el(s)); break; case 2: if (op2_ll != 0) { @@ -11203,6 +11211,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, dc->condjmp = 0; dc->aarch64 = 1; + dc->el3_is_aa64 = arm_el_is_aa64(env, 3); dc->thumb = 0; #if defined(TARGET_WORDS_BIGENDIAN) dc->bswap_code = 1; @@ -11320,7 +11329,8 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu, * bits should be zero. */ assert(num_insns == 1); - gen_exception(dc, EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0)); + gen_exception(dc, EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0), + default_exception_el(dc)); dc->is_jmp = DISAS_EXC; break; } diff --git a/qemu/target-arm/translate.c b/qemu/target-arm/translate.c index b4f95e1a..0d1c0980 100644 --- a/qemu/target-arm/translate.c +++ b/qemu/target-arm/translate.c @@ -210,13 +210,17 @@ static void gen_exception_internal(DisasContext *s, int excp) tcg_temp_free_i32(tcg_ctx, tcg_excp); } -static void gen_exception(DisasContext *s, int excp, uint32_t syndrome) // qq +static void gen_exception(DisasContext *s, int excp, uint32_t syndrome, uint32_t target_el) { TCGContext *tcg_ctx = s->uc->tcg_ctx; TCGv_i32 tcg_excp = tcg_const_i32(tcg_ctx, excp); TCGv_i32 tcg_syn = tcg_const_i32(tcg_ctx, syndrome); + TCGv_i32 tcg_el = tcg_const_i32(tcg_ctx, target_el); - gen_helper_exception_with_syndrome(tcg_ctx, tcg_ctx->cpu_env, tcg_excp, tcg_syn); + gen_helper_exception_with_syndrome(tcg_ctx, tcg_ctx->cpu_env, tcg_excp, + tcg_syn, tcg_el); + + tcg_temp_free_i32(tcg_ctx, tcg_el); tcg_temp_free_i32(tcg_ctx, tcg_syn); tcg_temp_free_i32(tcg_ctx, tcg_excp); } @@ -245,7 +249,8 @@ static void gen_step_complete_exception(DisasContext *s) * of the exception, and our syndrome information is always correct. */ gen_ss_advance(s); - gen_exception(s, EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex)); + gen_exception(s, EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex), + default_exception_el(s)); s->is_jmp = DISAS_EXC; } @@ -1081,11 +1086,12 @@ static void gen_exception_internal_insn(DisasContext *s, int offset, int excp) s->is_jmp = DISAS_JUMP; } -static void gen_exception_insn(DisasContext *s, int offset, int excp, int syn) +static void gen_exception_insn(DisasContext *s, int offset, int excp, + int syn, uint32_t target_el) { gen_set_condexec(s); gen_set_pc_im(s, s->pc - offset); - gen_exception(s, excp, syn); // qq + gen_exception(s, excp, syn, target_el); s->is_jmp = DISAS_JUMP; } @@ -3175,7 +3181,8 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) */ if (!s->cpacr_fpen) { gen_exception_insn(s, 4, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, s->thumb)); + syn_fp_access_trap(1, 0xe, s->thumb), + default_exception_el(s)); return 0; } @@ -4503,7 +4510,8 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) */ if (!s->cpacr_fpen) { gen_exception_insn(s, 4, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, s->thumb)); + syn_fp_access_trap(1, 0xe, s->thumb), + default_exception_el(s)); return 0; } @@ -5256,7 +5264,8 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) */ if (!s->cpacr_fpen) { gen_exception_insn(s, 4, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, s->thumb)); + syn_fp_access_trap(1, 0xe, s->thumb), + default_exception_el(s)); return 0; } @@ -8131,7 +8140,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq /* bkpt */ ARCH(5); gen_exception_insn(s, 4, EXCP_BKPT, - syn_aa32_bkpt(imm16, false)); + syn_aa32_bkpt(imm16, false), + default_exception_el(s)); break; case 2: /* Hypervisor call (v7) */ @@ -9200,7 +9210,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq break; default: illegal_op: - gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), + default_exception_el(s)); break; } } @@ -11159,7 +11170,8 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq { int imm8 = extract32(insn, 0, 8); ARCH(5); - gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true)); + gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true), + default_exception_el(s)); break; } @@ -11315,11 +11327,13 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq return; undef32: - gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized()); + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), + default_exception_el(s)); return; illegal_op: undef: - gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized()); + gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized(), + default_exception_el(s)); } /* generate intermediate code in gen_opc_buf and gen_opparam_buf for @@ -11363,6 +11377,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, dc->condjmp = 0; dc->aarch64 = 0; + dc->el3_is_aa64 = arm_el_is_aa64(env, 3); dc->thumb = ARM_TBFLAG_THUMB(tb->flags); // qq dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags); dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1; @@ -11543,7 +11558,8 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu, * bits should be zero. */ assert(num_insns == 1); - gen_exception(dc, EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0)); + gen_exception(dc, EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0), + default_exception_el(dc)); goto done_generating; } @@ -11616,13 +11632,14 @@ tb_end: gen_set_condexec(dc); if (dc->is_jmp == DISAS_SWI) { gen_ss_advance(dc); - gen_exception(dc, EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); + gen_exception(dc, EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb), + default_exception_el(dc)); } else if (dc->is_jmp == DISAS_HVC) { gen_ss_advance(dc); - gen_exception(dc, EXCP_HVC, syn_aa32_hvc(dc->svc_imm)); + gen_exception(dc, EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2); } else if (dc->is_jmp == DISAS_SMC) { gen_ss_advance(dc); - gen_exception(dc, EXCP_SMC, syn_aa32_smc()); + gen_exception(dc, EXCP_SMC, syn_aa32_smc(), 3); } else if (dc->ss_active) { gen_step_complete_exception(dc); } else { @@ -11637,13 +11654,14 @@ tb_end: gen_set_condexec(dc); if (dc->is_jmp == DISAS_SWI && !dc->condjmp) { gen_ss_advance(dc); - gen_exception(dc, EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); + gen_exception(dc, EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb), + default_exception_el(dc)); } else if (dc->is_jmp == DISAS_HVC && !dc->condjmp) { gen_ss_advance(dc); - gen_exception(dc, EXCP_HVC, syn_aa32_hvc(dc->svc_imm)); + gen_exception(dc, EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2); } else if (dc->is_jmp == DISAS_SMC && !dc->condjmp) { gen_ss_advance(dc); - gen_exception(dc, EXCP_SMC, syn_aa32_smc()); + gen_exception(dc, EXCP_SMC, syn_aa32_smc(), 3); } else if (dc->ss_active) { gen_step_complete_exception(dc); } else { @@ -11681,13 +11699,14 @@ tb_end: gen_helper_wfe(tcg_ctx, tcg_ctx->cpu_env); break; case DISAS_SWI: - gen_exception(dc, EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb)); + gen_exception(dc, EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb), + default_exception_el(dc)); break; case DISAS_HVC: - gen_exception(dc, EXCP_HVC, syn_aa32_hvc(dc->svc_imm)); + gen_exception(dc, EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2); break; case DISAS_SMC: - gen_exception(dc, EXCP_SMC, syn_aa32_smc()); + gen_exception(dc, EXCP_SMC, syn_aa32_smc(), 3); break; } if (dc->condjmp) { diff --git a/qemu/target-arm/translate.h b/qemu/target-arm/translate.h index ff8a74a8..eb05275d 100644 --- a/qemu/target-arm/translate.h +++ b/qemu/target-arm/translate.h @@ -23,6 +23,7 @@ typedef struct DisasContext { ARMMMUIdx mmu_idx; /* MMU index to use for normal loads/stores */ bool ns; /* Use non-secure CPREG bank on access */ bool cpacr_fpen; /* FP enabled via CPACR.FPEN */ + bool el3_is_aa64; /* Flag indicating whether EL3 is AArch64 or not */ bool vfp_enabled; /* FP enabled via FPSCR.EN */ int vec_len; int vec_stride; @@ -80,6 +81,20 @@ static inline int get_mem_index(DisasContext *s) return s->mmu_idx; } +/* Function used to determine the target exception EL when otherwise not known + * or default. + */ +static inline int default_exception_el(DisasContext *s) +{ + /* If we are coming from secure EL0 in a system with a 32-bit EL3, then + * there is no secure EL1, so we route exceptions to EL3. Otherwise, + * exceptions can only be routed to ELs above 1, so we target the higher of + * 1 or the current EL. + */ + return (s->mmu_idx == ARMMMUIdx_S1SE0 && !s->el3_is_aa64) + ? 3 : MAX(1, s->current_el); +} + /* target-specific extra values for is_jmp */ /* These instructions trap after executing, so the A32/T32 decoder must * defer them until after the conditional execution state has been updated.