target/arm: Create raise_exception_debug

Handle the debug vs current el exception test in one place.
Leave EXCP_BKPT alone, since that treats debug < current differently.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20220609202901.1177572-22-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2022-06-10 14:32:34 +01:00 committed by Peter Maydell
parent 82303761c6
commit 04eacf6e79
1 changed files with 24 additions and 20 deletions

View File

@ -12,6 +12,26 @@
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
/*
* Raise an exception to the debug target el.
* Modify syndrome to indicate when origin and target EL are the same.
*/
G_NORETURN static void
raise_exception_debug(CPUARMState *env, uint32_t excp, uint32_t syndrome)
{
int debug_el = arm_debug_target_el(env);
int cur_el = arm_current_el(env);
/*
* If singlestep is targeting a lower EL than the current one, then
* DisasContext.ss_active must be false and we can never get here.
* Similarly for watchpoint and breakpoint matches.
*/
assert(debug_el >= cur_el);
syndrome |= (debug_el == cur_el) << ARM_EL_EC_SHIFT;
raise_exception(env, excp, syndrome, debug_el);
}
/* See AArch64.GenerateDebugExceptionsFrom() in ARM ARM pseudocode */ /* See AArch64.GenerateDebugExceptionsFrom() in ARM ARM pseudocode */
static bool aa64_generate_debug_exceptions(CPUARMState *env) static bool aa64_generate_debug_exceptions(CPUARMState *env)
{ {
@ -418,19 +438,16 @@ void arm_debug_excp_handler(CPUState *cs)
if (wp_hit) { if (wp_hit) {
if (wp_hit->flags & BP_CPU) { if (wp_hit->flags & BP_CPU) {
bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0; 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; cs->watchpoint_hit = NULL;
env->exception.fsr = arm_debug_exception_fsr(env); env->exception.fsr = arm_debug_exception_fsr(env);
env->exception.vaddress = wp_hit->hitaddr; env->exception.vaddress = wp_hit->hitaddr;
raise_exception(env, EXCP_DATA_ABORT, raise_exception_debug(env, EXCP_DATA_ABORT,
syn_watchpoint(same_el, 0, wnr), syn_watchpoint(0, 0, wnr));
arm_debug_target_el(env));
} }
} else { } else {
uint64_t pc = is_a64(env) ? env->pc : env->regs[15]; 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. * (1) GDB breakpoints should be handled first.
@ -450,9 +467,7 @@ void arm_debug_excp_handler(CPUState *cs)
* exception/security level. * exception/security level.
*/ */
env->exception.vaddress = 0; env->exception.vaddress = 0;
raise_exception(env, EXCP_PREFETCH_ABORT, raise_exception_debug(env, EXCP_PREFETCH_ABORT, syn_breakpoint(0));
syn_breakpoint(same_el),
arm_debug_target_el(env));
} }
} }
@ -489,18 +504,7 @@ void HELPER(exception_bkpt_insn)(CPUARMState *env, uint32_t syndrome)
void HELPER(exception_swstep)(CPUARMState *env, uint32_t syndrome) void HELPER(exception_swstep)(CPUARMState *env, uint32_t syndrome)
{ {
int debug_el = arm_debug_target_el(env); raise_exception_debug(env, EXCP_UDEF, syndrome);
int cur_el = arm_current_el(env);
/*
* If singlestep is targeting a lower EL than the current one, then
* DisasContext.ss_active must be false and we can never get here.
*/
assert(debug_el >= cur_el);
if (debug_el == cur_el) {
syndrome |= 1 << ARM_EL_EC_SHIFT;
}
raise_exception(env, EXCP_UDEF, syndrome, debug_el);
} }
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)