target/arm: Factor out code for taking an AArch32 exception

Factor out the code which changes the CPU state so as to
actually take an exception to AArch32. We're going to want
to use this for handling exception entry to Hyp mode.

Backports commit dea8378bb3e86f2c6bd05afb3927619f7c51bb47 from qemu
This commit is contained in:
Peter Maydell 2018-08-25 04:23:50 -04:00 committed by Lioncash
parent c238d5cc6b
commit 4c445c2300
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -7231,6 +7231,46 @@ void aarch64_sync_64_to_32(CPUARMState *env)
env->regs[15] = env->pc;
}
static void take_aarch32_exception(CPUARMState *env, int new_mode,
uint32_t mask, uint32_t offset,
uint32_t newpc)
{
/* Change the CPU state so as to actually take the exception. */
switch_mode(env, new_mode);
/*
* For exceptions taken to AArch32 we must clear the SS bit in both
* PSTATE and in the old-state value we save to SPSR_<mode>, so zero it now.
*/
env->uncached_cpsr &= ~PSTATE_SS;
env->spsr = cpsr_read(env);
/* Clear IT bits. */
env->condexec_bits = 0;
/* Switch to the new mode, and to the correct instruction set. */
env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
/* Set new mode endianness */
env->uncached_cpsr &= ~CPSR_E;
if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
env->uncached_cpsr |= CPSR_E;
}
env->daif |= mask;
if (new_mode == ARM_CPU_MODE_HYP) {
env->thumb = (env->cp15.sctlr_el[2] & SCTLR_TE) != 0;
env->elr_el[2] = env->regs[15];
} else {
/*
* this is a lie, as there was no c1_sys on V4T/V5, but who cares
* and we should just guard the thumb mode on V4
*/
if (arm_feature(env, ARM_FEATURE_V4T)) {
env->thumb =
(A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0;
}
env->regs[14] = env->regs[15] + offset;
}
env->regs[15] = newpc;
}
// Unicorn: underscore appended to prevent silly clashing with defines
static void arm_cpu_do_interrupt_aarch32_(CPUState *cs)
{
@ -7373,29 +7413,7 @@ static void arm_cpu_do_interrupt_aarch32_(CPUState *cs)
env->cp15.scr_el3 &= ~SCR_NS;
}
switch_mode (env, new_mode);
/* For exceptions taken to AArch32 we must clear the SS bit in both
* PSTATE and in the old-state value we save to SPSR_<mode>, so zero it now.
*/
env->uncached_cpsr &= ~PSTATE_SS;
env->spsr = cpsr_read(env);
/* Clear IT bits. */
env->condexec_bits = 0;
/* Switch to the new mode, and to the correct instruction set. */
env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
/* Set new mode endianness */
env->uncached_cpsr &= ~CPSR_E;
if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
env->uncached_cpsr |= CPSR_E;
}
env->daif |= mask;
/* this is a lie, as the was no c1_sys on V4T/V5, but who cares
* and we should just guard the thumb mode on V4 */
if (arm_feature(env, ARM_FEATURE_V4T)) {
env->thumb = (A32_BANKED_CURRENT_REG_GET(env, sctlr) & SCTLR_TE) != 0;
}
env->regs[14] = env->regs[15] + offset;
env->regs[15] = addr;
take_aarch32_exception(env, new_mode, mask, offset, addr);
}
/* Handle exception entry to a target EL which is using AArch64 */