summaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/arm/helper.c1
-rw-r--r--target/arm/helper.h1
-rw-r--r--target/arm/internals.h25
-rw-r--r--target/arm/op_helper.c33
-rw-r--r--target/arm/translate-a64.c21
-rw-r--r--target/arm/translate.c19
6 files changed, 78 insertions, 22 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 09893e3f72..dcb8476d9e 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7910,7 +7910,6 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
offset = 0;
break;
case EXCP_BKPT:
- env->exception.fsr = 2;
/* Fall through to prefetch abort. */
case EXCP_PREFETCH_ABORT:
A32_BANKED_CURRENT_REG_SET(env, ifsr, env->exception.fsr);
diff --git a/target/arm/helper.h b/target/arm/helper.h
index 0d2094f2be..34e8cc8904 100644
--- a/target/arm/helper.h
+++ b/target/arm/helper.h
@@ -47,6 +47,7 @@ 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_4(exception_with_syndrome, void, env, i32, i32, i32)
+DEF_HELPER_2(exception_bkpt_insn, void, env, i32)
DEF_HELPER_1(setend, void, env)
DEF_HELPER_2(wfi, void, env, i32)
DEF_HELPER_1(wfe, void, env)
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 47cc224a46..8ce944b7a0 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -763,4 +763,29 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
}
}
+/* Return the FSR value for a debug exception (watchpoint, hardware
+ * breakpoint or BKPT insn) targeting the specified exception level.
+ */
+static inline uint32_t arm_debug_exception_fsr(CPUARMState *env)
+{
+ ARMMMUFaultInfo fi = { .type = ARMFault_Debug };
+ int target_el = arm_debug_target_el(env);
+ bool using_lpae = false;
+
+ if (target_el == 2 || arm_el_is_aa64(env, target_el)) {
+ using_lpae = true;
+ } else {
+ if (arm_feature(env, ARM_FEATURE_LPAE) &&
+ (env->cp15.tcr_el[target_el].raw_tcr & TTBCR_EAE)) {
+ using_lpae = true;
+ }
+ }
+
+ if (using_lpae) {
+ return arm_fi_to_lfsc(&fi);
+ } else {
+ return arm_fi_to_sfsc(&fi);
+ }
+}
+
#endif
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 7a88fd2c92..a266cc0116 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -483,6 +483,21 @@ void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp,
raise_exception(env, excp, syndrome, target_el);
}
+/* Raise an EXCP_BKPT with the specified syndrome register value,
+ * targeting the correct exception level for debug exceptions.
+ */
+void HELPER(exception_bkpt_insn)(CPUARMState *env, uint32_t syndrome)
+{
+ /* FSR will only be used if the debug target EL is AArch32. */
+ env->exception.fsr = arm_debug_exception_fsr(env);
+ /* FAR is UNKNOWN: clear vaddress to avoid potentially exposing
+ * values to the guest that it shouldn't be able to see at its
+ * exception/security level.
+ */
+ env->exception.vaddress = 0;
+ raise_exception(env, EXCP_BKPT, syndrome, arm_debug_target_el(env));
+}
+
uint32_t HELPER(cpsr_read)(CPUARMState *env)
{
return cpsr_read(env) & ~(CPSR_EXEC | CPSR_RESERVED);
@@ -1322,11 +1337,7 @@ void arm_debug_excp_handler(CPUState *cs)
cs->watchpoint_hit = NULL;
- if (extended_addresses_enabled(env)) {
- env->exception.fsr = (1 << 9) | 0x22;
- } else {
- env->exception.fsr = 0x2;
- }
+ env->exception.fsr = arm_debug_exception_fsr(env);
env->exception.vaddress = wp_hit->hitaddr;
raise_exception(env, EXCP_DATA_ABORT,
syn_watchpoint(same_el, 0, wnr),
@@ -1346,12 +1357,12 @@ void arm_debug_excp_handler(CPUState *cs)
return;
}
- if (extended_addresses_enabled(env)) {
- env->exception.fsr = (1 << 9) | 0x22;
- } else {
- env->exception.fsr = 0x2;
- }
- /* FAR is UNKNOWN, so doesn't need setting */
+ env->exception.fsr = arm_debug_exception_fsr(env);
+ /* FAR is UNKNOWN: clear vaddress to avoid potentially exposing
+ * values to the guest that it shouldn't be able to see at its
+ * exception/security level.
+ */
+ env->exception.vaddress = 0;
raise_exception(env, EXCP_PREFETCH_ABORT,
syn_breakpoint(same_el),
arm_debug_target_el(env));
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 31ff0479e6..c91329249d 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -321,6 +321,18 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
s->base.is_jmp = DISAS_NORETURN;
}
+static void gen_exception_bkpt_insn(DisasContext *s, int offset,
+ uint32_t syndrome)
+{
+ TCGv_i32 tcg_syn;
+
+ gen_a64_set_pc_im(s->pc - offset);
+ tcg_syn = tcg_const_i32(syndrome);
+ gen_helper_exception_bkpt_insn(cpu_env, tcg_syn);
+ tcg_temp_free_i32(tcg_syn);
+ s->base.is_jmp = DISAS_NORETURN;
+}
+
static void gen_ss_advance(DisasContext *s)
{
/* If the singlestep state is Active-not-pending, advance to
@@ -1839,8 +1851,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
break;
}
/* BRK */
- gen_exception_insn(s, 4, EXCP_BKPT, syn_aa64_bkpt(imm16),
- default_exception_el(s));
+ gen_exception_bkpt_insn(s, 4, syn_aa64_bkpt(imm16));
break;
case 2:
if (op2_ll != 0) {
@@ -13378,12 +13389,12 @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
case DISAS_UPDATE:
gen_a64_set_pc_im(dc->pc);
/* fall through */
- case DISAS_JUMP:
- tcg_gen_lookup_and_goto_ptr();
- break;
case DISAS_EXIT:
tcg_gen_exit_tb(0);
break;
+ case DISAS_JUMP:
+ tcg_gen_lookup_and_goto_ptr();
+ break;
case DISAS_NORETURN:
case DISAS_SWI:
break;
diff --git a/target/arm/translate.c b/target/arm/translate.c
index ba6ab7d287..fc03b5b8c8 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -1248,6 +1248,18 @@ static void gen_exception_insn(DisasContext *s, int offset, int excp,
s->base.is_jmp = DISAS_NORETURN;
}
+static void gen_exception_bkpt_insn(DisasContext *s, int offset, uint32_t syn)
+{
+ TCGv_i32 tcg_syn;
+
+ gen_set_condexec(s);
+ gen_set_pc_im(s, s->pc - offset);
+ tcg_syn = tcg_const_i32(syn);
+ gen_helper_exception_bkpt_insn(cpu_env, tcg_syn);
+ tcg_temp_free_i32(tcg_syn);
+ s->base.is_jmp = DISAS_NORETURN;
+}
+
/* Force a TB lookup after an instruction that changes the CPU state. */
static inline void gen_lookup_tb(DisasContext *s)
{
@@ -8774,9 +8786,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
case 1:
/* bkpt */
ARCH(5);
- gen_exception_insn(s, 4, EXCP_BKPT,
- syn_aa32_bkpt(imm16, false),
- default_exception_el(s));
+ gen_exception_bkpt_insn(s, 4, syn_aa32_bkpt(imm16, false));
break;
case 2:
/* Hypervisor call (v7) */
@@ -11983,8 +11993,7 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
{
int imm8 = extract32(insn, 0, 8);
ARCH(5);
- gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true),
- default_exception_el(s));
+ gen_exception_bkpt_insn(s, 2, syn_aa32_bkpt(imm8, true));
break;
}