@@ -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.
*/
@@ -47,7 +47,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)
@@ -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;
env->exception.syndrome = syndrome;
+ env->exception.target_el = target_el;
cpu_loop_exit(cs);
}
@@ -197,12 +197,15 @@ static void gen_exception_internal(int excp)
tcg_temp_free_i32(tcg_excp);
}
-static void gen_exception(int excp, uint32_t syndrome)
+static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el)
{
TCGv_i32 tcg_excp = tcg_const_i32(excp);
TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
+ TCGv_i32 tcg_el = tcg_const_i32(MAX(target_el, 1));
- gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn);
+ gen_helper_exception_with_syndrome(cpu_env, tcg_excp,
+ tcg_syn, tcg_el);
+ tcg_temp_free_i32(tcg_el);
tcg_temp_free_i32(tcg_syn);
tcg_temp_free_i32(tcg_excp);
}
@@ -215,10 +218,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->pc - offset);
- gen_exception(excp, syndrome);
+ gen_exception(excp, syndrome, target_el);
s->is_jmp = DISAS_EXC;
}
@@ -245,7 +248,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(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex));
+ gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
+ s->current_el);
s->is_jmp = DISAS_EXC;
}
@@ -292,7 +296,7 @@ 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(), s->current_el);
}
#define unsupported_encoding(s, insn) \
@@ -971,7 +975,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),
+ s->current_el);
return false;
}
@@ -1498,7 +1503,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),
+ s->current_el);
break;
case 2:
if (s->current_el == 0) {
@@ -1511,7 +1517,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
gen_a64_set_pc_im(s->pc - 4);
gen_helper_pre_hvc(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) {
@@ -1523,7 +1529,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
gen_helper_pre_smc(cpu_env, tmp);
tcg_temp_free_i32(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);
@@ -1536,7 +1542,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),
+ s->current_el);
break;
case 2:
if (op2_ll != 0) {
@@ -11031,7 +11038,8 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
* bits should be zero.
*/
assert(num_insns == 0);
- gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0));
+ gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
+ dc->current_el);
dc->is_jmp = DISAS_EXC;
break;
}
@@ -217,12 +217,16 @@ static void gen_exception_internal(int excp)
tcg_temp_free_i32(tcg_excp);
}
-static void gen_exception(int excp, uint32_t syndrome)
+static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el)
{
TCGv_i32 tcg_excp = tcg_const_i32(excp);
TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
+ TCGv_i32 tcg_el = tcg_const_i32(MAX(target_el, 1));
- gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn);
+ gen_helper_exception_with_syndrome(cpu_env, tcg_excp,
+ tcg_syn, tcg_el);
+
+ tcg_temp_free_i32(tcg_el);
tcg_temp_free_i32(tcg_syn);
tcg_temp_free_i32(tcg_excp);
}
@@ -250,7 +254,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(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex));
+ gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
+ s->current_el);
s->is_jmp = DISAS_EXC;
}
@@ -1013,11 +1018,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(excp, syn);
+ gen_exception(excp, syn, target_el);
s->is_jmp = DISAS_JUMP;
}
@@ -3040,7 +3046,7 @@ 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), s->current_el);
return 0;
}
@@ -4358,7 +4364,7 @@ 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), s->current_el);
return 0;
}
@@ -5096,7 +5102,7 @@ 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), s->current_el);
return 0;
}
@@ -7960,7 +7966,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
/* bkpt */
ARCH(5);
gen_exception_insn(s, 4, EXCP_BKPT,
- syn_aa32_bkpt(imm16, false));
+ syn_aa32_bkpt(imm16, false), s->current_el);
break;
case 2:
/* Hypervisor call (v7) */
@@ -9021,7 +9027,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
break;
default:
illegal_op:
- gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
+ gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
+ s->current_el);
break;
}
}
@@ -10858,7 +10865,8 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
{
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),
+ s->current_el);
break;
}
@@ -11013,11 +11021,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
}
return;
undef32:
- gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
+ gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
+ s->current_el);
return;
illegal_op:
undef:
- gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized());
+ gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized(), s->current_el);
}
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
@@ -11216,7 +11225,8 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
* bits should be zero.
*/
assert(num_insns == 0);
- gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0));
+ gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
+ dc->current_el);
goto done_generating;
}
@@ -11276,13 +11286,14 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
gen_set_condexec(dc);
if (dc->is_jmp == DISAS_SWI) {
gen_ss_advance(dc);
- gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
+ gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
+ dc->current_el);
} else if (dc->is_jmp == DISAS_HVC) {
gen_ss_advance(dc);
- gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm));
+ gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
} else if (dc->is_jmp == DISAS_SMC) {
gen_ss_advance(dc);
- gen_exception(EXCP_SMC, syn_aa32_smc());
+ gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
} else if (dc->ss_active) {
gen_step_complete_exception(dc);
} else {
@@ -11297,13 +11308,14 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
gen_set_condexec(dc);
if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
gen_ss_advance(dc);
- gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
+ gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
+ dc->current_el);
} else if (dc->is_jmp == DISAS_HVC && !dc->condjmp) {
gen_ss_advance(dc);
- gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm));
+ gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
} else if (dc->is_jmp == DISAS_SMC && !dc->condjmp) {
gen_ss_advance(dc);
- gen_exception(EXCP_SMC, syn_aa32_smc());
+ gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
} else if (dc->ss_active) {
gen_step_complete_exception(dc);
} else {
@@ -11341,13 +11353,14 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
gen_helper_wfe(cpu_env);
break;
case DISAS_SWI:
- gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
+ gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
+ dc->current_el);
break;
case DISAS_HVC:
- gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm));
+ gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
break;
case DISAS_SMC:
- gen_exception(EXCP_SMC, syn_aa32_smc());
+ gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
break;
}
if (dc->condjmp) {
Add a CPU state exception target EL field that will be used for communicating the EL to which an exception should be routed. Add a target EL argument to the generic exception helper for callers to specify the EL to which the exception should be routed. Extended the helper to set the newly added CPU state exception target el. Updated calls to helpers to include target EL, minimally the current el, which gets upgraded as needed. Signed-off-by: Greg Bellows <greg.bellows@linaro.org> --- target-arm/cpu.h | 1 + target-arm/helper.h | 2 +- target-arm/op_helper.c | 3 ++- target-arm/translate-a64.c | 32 +++++++++++++++---------- target-arm/translate.c | 59 ++++++++++++++++++++++++++++------------------ 5 files changed, 60 insertions(+), 37 deletions(-)