mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-24 20:19:44 +00:00
target-arm: Set PSTATE.SS correctly on exception return from AArch64
Set the PSTATE.SS bit correctly on exception returns from AArch64, as required by the debug single-step functionality. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
This commit is contained in:
parent
662cefb775
commit
3a2982038a
@ -220,6 +220,7 @@ typedef struct CPUARMState {
|
||||
uint64_t dbgbcr[16]; /* breakpoint control registers */
|
||||
uint64_t dbgwvr[16]; /* watchpoint value registers */
|
||||
uint64_t dbgwcr[16]; /* watchpoint control registers */
|
||||
uint64_t mdscr_el1;
|
||||
/* If the counter is enabled, this stores the last time the counter
|
||||
* was reset. Otherwise it stores the counter value
|
||||
*/
|
||||
@ -1119,6 +1120,66 @@ static inline int cpu_mmu_index (CPUARMState *env)
|
||||
return arm_current_pl(env);
|
||||
}
|
||||
|
||||
/* Return the Exception Level targeted by debug exceptions;
|
||||
* currently always EL1 since we don't implement EL2 or EL3.
|
||||
*/
|
||||
static inline int arm_debug_target_el(CPUARMState *env)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool aa64_generate_debug_exceptions(CPUARMState *env)
|
||||
{
|
||||
if (arm_current_pl(env) == arm_debug_target_el(env)) {
|
||||
if ((extract32(env->cp15.mdscr_el1, 13, 1) == 0)
|
||||
|| (env->daif & PSTATE_D)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool aa32_generate_debug_exceptions(CPUARMState *env)
|
||||
{
|
||||
if (arm_current_pl(env) == 0 && arm_el_is_aa64(env, 1)) {
|
||||
return aa64_generate_debug_exceptions(env);
|
||||
}
|
||||
return arm_current_pl(env) != 2;
|
||||
}
|
||||
|
||||
/* Return true if debugging exceptions are currently enabled.
|
||||
* This corresponds to what in ARM ARM pseudocode would be
|
||||
* if UsingAArch32() then
|
||||
* return AArch32.GenerateDebugExceptions()
|
||||
* else
|
||||
* return AArch64.GenerateDebugExceptions()
|
||||
* We choose to push the if() down into this function for clarity,
|
||||
* since the pseudocode has it at all callsites except for the one in
|
||||
* CheckSoftwareStep(), where it is elided because both branches would
|
||||
* always return the same value.
|
||||
*
|
||||
* Parts of the pseudocode relating to EL2 and EL3 are omitted because we
|
||||
* don't yet implement those exception levels or their associated trap bits.
|
||||
*/
|
||||
static inline bool arm_generate_debug_exceptions(CPUARMState *env)
|
||||
{
|
||||
if (env->aarch64) {
|
||||
return aa64_generate_debug_exceptions(env);
|
||||
} else {
|
||||
return aa32_generate_debug_exceptions(env);
|
||||
}
|
||||
}
|
||||
|
||||
/* Is single-stepping active? (Note that the "is EL_D AArch64?" check
|
||||
* implicitly means this always returns false in pre-v8 CPUs.)
|
||||
*/
|
||||
static inline bool arm_singlestep_active(CPUARMState *env)
|
||||
{
|
||||
return extract32(env->cp15.mdscr_el1, 0, 1)
|
||||
&& arm_el_is_aa64(env, arm_debug_target_el(env))
|
||||
&& arm_generate_debug_exceptions(env);
|
||||
}
|
||||
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
/* Bit usage in the TB flags field: bit 31 indicates whether we are
|
||||
|
@ -380,12 +380,26 @@ void HELPER(exception_return)(CPUARMState *env)
|
||||
|
||||
env->exclusive_addr = -1;
|
||||
|
||||
/* We must squash the PSTATE.SS bit to zero unless both of the
|
||||
* following hold:
|
||||
* 1. debug exceptions are currently disabled
|
||||
* 2. singlestep will be active in the EL we return to
|
||||
* We check 1 here and 2 after we've done the pstate/cpsr write() to
|
||||
* transition to the EL we're going to.
|
||||
*/
|
||||
if (arm_generate_debug_exceptions(env)) {
|
||||
spsr &= ~PSTATE_SS;
|
||||
}
|
||||
|
||||
if (spsr & PSTATE_nRW) {
|
||||
/* TODO: We currently assume EL1/2/3 are running in AArch64. */
|
||||
env->aarch64 = 0;
|
||||
new_el = 0;
|
||||
env->uncached_cpsr = 0x10;
|
||||
cpsr_write(env, spsr, ~0);
|
||||
if (!arm_singlestep_active(env)) {
|
||||
env->uncached_cpsr &= ~PSTATE_SS;
|
||||
}
|
||||
for (i = 0; i < 15; i++) {
|
||||
env->regs[i] = env->xregs[i];
|
||||
}
|
||||
@ -410,6 +424,9 @@ void HELPER(exception_return)(CPUARMState *env)
|
||||
}
|
||||
env->aarch64 = 1;
|
||||
pstate_write(env, spsr);
|
||||
if (!arm_singlestep_active(env)) {
|
||||
env->pstate &= ~PSTATE_SS;
|
||||
}
|
||||
aarch64_restore_sp(env, new_el);
|
||||
env->pc = env->elr_el[cur_el];
|
||||
}
|
||||
@ -429,6 +446,9 @@ illegal_return:
|
||||
spsr &= PSTATE_NZCV | PSTATE_DAIF;
|
||||
spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
|
||||
pstate_write(env, spsr);
|
||||
if (!arm_singlestep_active(env)) {
|
||||
env->pstate &= ~PSTATE_SS;
|
||||
}
|
||||
}
|
||||
|
||||
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
|
||||
|
Loading…
Reference in New Issue
Block a user