aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-08-24 13:17:37 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-08-24 13:17:37 +0100
commitdea8378bb3e86f2c6bd05afb3927619f7c51bb47 (patch)
treed05ca9859df6dcff1c161793ca8b65deb249d286 /target
parentce4afed8396aabaf87cd42fbe8a4c14f7a9d5c10 (diff)
downloadqemu-dea8378bb3e86f2c6bd05afb3927619f7c51bb47.zip
qemu-dea8378bb3e86f2c6bd05afb3927619f7c51bb47.tar.gz
qemu-dea8378bb3e86f2c6bd05afb3927619f7c51bb47.tar.bz2
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. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com> Reviewed-by: Luc Michel <luc.michel@greensocs.com> Message-id: 20180820153020.21478-4-peter.maydell@linaro.org
Diffstat (limited to 'target')
-rw-r--r--target/arm/helper.c64
1 files changed, 41 insertions, 23 deletions
diff --git a/target/arm/helper.c b/target/arm/helper.c
index f0f5fe6..48ec46a 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8033,6 +8033,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;
+}
+
static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
@@ -8175,29 +8215,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 */