@@ -125,6 +125,14 @@ G_NORETURN void raise_exception_ra(CPUARMState *env, uint32_t excp,
uint32_t syndrome,
uint32_t cur_or_target_el, uintptr_t ra);
+/**
+ * raise_exception_debug:
+ * Similarly. If @excp != EXCPBKPT, modify syndrome to indicate
+ * when origin and target EL are the same.
+ */
+G_NORETURN void raise_exception_debug(CPUARMState *env, uint32_t excp,
+ uint32_t syndrome);
+
/*
* For AArch64, map a given EL to an index in the banked_spsr array.
* Note that this mapping and the AArch32 mapping defined in bank_number()
@@ -417,19 +417,16 @@ void arm_debug_excp_handler(CPUState *cs)
if (wp_hit) {
if (wp_hit->flags & BP_CPU) {
bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0;
- bool same_el = arm_debug_target_el(env) == arm_current_el(env);
cs->watchpoint_hit = NULL;
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),
- arm_debug_target_el(env));
+ raise_exception_debug(env, EXCP_DATA_ABORT,
+ syn_watchpoint(0, 0, wnr));
}
} else {
uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
- bool same_el = (arm_debug_target_el(env) == arm_current_el(env));
/*
* (1) GDB breakpoints should be handled first.
@@ -449,9 +446,7 @@ void arm_debug_excp_handler(CPUState *cs)
* exception/security level.
*/
env->exception.vaddress = 0;
- raise_exception(env, EXCP_PREFETCH_ABORT,
- syn_breakpoint(same_el),
- arm_debug_target_el(env));
+ raise_exception_debug(env, EXCP_PREFETCH_ABORT, syn_breakpoint(0));
}
}
@@ -461,9 +456,6 @@ void arm_debug_excp_handler(CPUState *cs)
*/
void HELPER(exception_bkpt_insn)(CPUARMState *env, uint32_t syndrome)
{
- int debug_el = arm_debug_target_el(env);
- int cur_el = arm_current_el(env);
-
/* FSR will only be used if the debug target EL is AArch32. */
env->exception.fsr = arm_debug_exception_fsr(env);
/*
@@ -472,18 +464,7 @@ void HELPER(exception_bkpt_insn)(CPUARMState *env, uint32_t syndrome)
* exception/security level.
*/
env->exception.vaddress = 0;
- /*
- * Other kinds of architectural debug exception are ignored if
- * they target an exception level below the current one (in QEMU
- * this is checked by arm_generate_debug_exceptions()). Breakpoint
- * instructions are special because they always generate an exception
- * to somewhere: if they can't go to the configured debug exception
- * level they are taken to the current exception level.
- */
- if (debug_el < cur_el) {
- debug_el = cur_el;
- }
- raise_exception(env, EXCP_BKPT, syndrome, debug_el);
+ raise_exception_debug(env, EXCP_BKPT, syndrome);
}
#if !defined(CONFIG_USER_ONLY)
@@ -65,15 +65,11 @@ int exception_target_el(CPUARMState *env, int cur_el, uint32_t *psyn)
return 1;
}
-void raise_exception(CPUARMState *env, uint32_t excp, uint32_t syndrome,
- uint32_t cur_or_target_el)
+G_NORETURN static
+void raise_exception_int(CPUARMState *env, uint32_t excp,
+ uint32_t syndrome, uint32_t target_el)
{
CPUState *cs = env_cpu(env);
- int target_el = cur_or_target_el;
-
- if (cur_or_target_el <= 1) {
- target_el = exception_target_el(env, cur_or_target_el, &syndrome);
- }
assert(!excp_is_internal(excp));
cs->exception_index = excp;
@@ -82,6 +78,39 @@ void raise_exception(CPUARMState *env, uint32_t excp, uint32_t syndrome,
cpu_loop_exit(cs);
}
+void raise_exception(CPUARMState *env, uint32_t excp, uint32_t syndrome,
+ uint32_t cur_or_target_el)
+{
+ int target_el = cur_or_target_el;
+ if (cur_or_target_el <= 1) {
+ target_el = exception_target_el(env, cur_or_target_el, &syndrome);
+ }
+ raise_exception_int(env, excp, syndrome, target_el);
+}
+
+void raise_exception_debug(CPUARMState *env, uint32_t excp, uint32_t syndrome)
+{
+ int cur_el = arm_current_el(env);
+ int debug_el = arm_debug_target_el(env);
+
+ /*
+ * Most kinds of architectural debug exception are ignored if
+ * they target an exception level below the current (in QEMU
+ * this is checked by arm_generate_debug_exceptions()).
+ * Breakpoint instructions are special because they always generate
+ * an exception to somewhere: if they can't go to the configured
+ * debug exception level they are taken to the current exception level.
+ */
+ if (excp == EXCP_BKPT) {
+ debug_el = MAX(cur_el, debug_el);
+ } else {
+ assert(debug_el >= cur_el);
+ syndrome |= (debug_el == cur_el) << ARM_EL_EC_SHIFT;
+ }
+
+ raise_exception_int(env, excp, syndrome, debug_el);
+}
+
void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome,
uint32_t cur_or_target_el, uintptr_t ra)
{
Handle EL testing for debug exceptions in a single place. Split out raise_exception_int as a common helper. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/arm/internals.h | 8 ++++++++ target/arm/debug_helper.c | 27 ++++-------------------- target/arm/op_helper.c | 43 ++++++++++++++++++++++++++++++++------- 3 files changed, 48 insertions(+), 30 deletions(-)