summaryrefslogtreecommitdiffstats
path: root/target-arm/helper-a64.c
diff options
context:
space:
mode:
authorPeter Maydell2014-04-17 22:37:26 +0200
committerPeter Maydell2014-04-17 22:37:26 +0200
commit2d03b49c3f225994c4b0b46146437d8c887d6774 (patch)
tree00663246afe656b777e3c218cfea25e7ed32ffc2 /target-arm/helper-a64.c
parentMerge remote-tracking branch 'remotes/rth/tcg-aarch-6-5' into staging (diff)
parenttarget-arm: A64: fix unallocated test of scalar SQXTUN (diff)
downloadqemu-2d03b49c3f225994c4b0b46146437d8c887d6774.tar.gz
qemu-2d03b49c3f225994c4b0b46146437d8c887d6774.tar.xz
qemu-2d03b49c3f225994c4b0b46146437d8c887d6774.zip
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140417-1' into staging
target-arm queue: * AArch64 system mode support; this is all the CPU emulation code but not the virt board support * cadence_ttc match register bugfix * Allwinner A10 PIC, PIT and ethernet fixes [with update to avoid duplicate typedef] * zynq-slcr rewrite * cadence_gem bugfix * fix for SMLALD/SMLSLD insn in A32 * fix for SQXTUN in A64 # gpg: Signature made Thu 17 Apr 2014 21:35:57 BST using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20140417-1: (51 commits) target-arm: A64: fix unallocated test of scalar SQXTUN arm: translate.c: Fix smlald Instruction net: cadence_gem: Make phy respond to broadcast misc: zynq_slcr: Make DB_PRINTs always compile misc: zynq_slcr: Convert SBD::init to object init misc: zynq-slcr: Rewrite allwinner-emac: update irq status after writes to interrupt registers allwinner-emac: set autonegotiation complete bit on link up allwinner-a10-pit: implement prescaler and source selection allwinner-a10-pit: use level triggered interrupts allwinner-a10-pit: avoid generation of spurious interrupts allwinner-a10-pic: fix behaviour of pending register allwinner-a10-pic: set vector address when an interrupt is pending timer: cadence_ttc: Fix match register write logic target-arm/gdbstub64.c: remove useless 'break' statement. target-arm: Dump 32-bit CPU state if 64 bit CPU is in AArch32 target-arm: Handle the CPU being in AArch32 mode in the AArch64 set_pc target-arm: Make Cortex-A15 CBAR read-only target-arm: Implement CBAR for Cortex-A57 target-arm: Implement Cortex-A57 implementation-defined system registers ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm/helper-a64.c')
-rw-r--r--target-arm/helper-a64.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index ec0258295f..bf921ccdc0 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -23,6 +23,7 @@
#include "qemu/host-utils.h"
#include "sysemu/sysemu.h"
#include "qemu/bitops.h"
+#include "internals.h"
/* C2.4.7 Multiply and divide */
/* special cases for 0 and LLONG_MIN are mandated by the standard */
@@ -436,3 +437,78 @@ float32 HELPER(fcvtx_f64_to_f32)(float64 a, CPUARMState *env)
set_float_exception_flags(exflags, fpst);
return r;
}
+
+/* Handle a CPU exception. */
+void aarch64_cpu_do_interrupt(CPUState *cs)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ target_ulong addr = env->cp15.c12_vbar;
+ int i;
+
+ if (arm_current_pl(env) == 0) {
+ if (env->aarch64) {
+ addr += 0x400;
+ } else {
+ addr += 0x600;
+ }
+ } else if (pstate_read(env) & PSTATE_SP) {
+ addr += 0x200;
+ }
+
+ arm_log_exception(cs->exception_index);
+ qemu_log_mask(CPU_LOG_INT, "...from EL%d\n", arm_current_pl(env));
+ if (qemu_loglevel_mask(CPU_LOG_INT)
+ && !excp_is_internal(cs->exception_index)) {
+ qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n",
+ env->exception.syndrome);
+ }
+
+ env->cp15.esr_el1 = env->exception.syndrome;
+ env->cp15.far_el1 = env->exception.vaddress;
+
+ switch (cs->exception_index) {
+ case EXCP_PREFETCH_ABORT:
+ case EXCP_DATA_ABORT:
+ qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
+ env->cp15.far_el1);
+ break;
+ case EXCP_BKPT:
+ case EXCP_UDEF:
+ case EXCP_SWI:
+ break;
+ case EXCP_IRQ:
+ addr += 0x80;
+ break;
+ case EXCP_FIQ:
+ addr += 0x100;
+ break;
+ default:
+ cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
+ }
+
+ if (is_a64(env)) {
+ env->banked_spsr[0] = pstate_read(env);
+ env->sp_el[arm_current_pl(env)] = env->xregs[31];
+ env->xregs[31] = env->sp_el[1];
+ env->elr_el1 = env->pc;
+ } else {
+ env->banked_spsr[0] = cpsr_read(env);
+ if (!env->thumb) {
+ env->cp15.esr_el1 |= 1 << 25;
+ }
+ env->elr_el1 = env->regs[15];
+
+ for (i = 0; i < 15; i++) {
+ env->xregs[i] = env->regs[i];
+ }
+
+ env->condexec_bits = 0;
+ }
+
+ pstate_write(env, PSTATE_DAIF | PSTATE_MODE_EL1h);
+ env->aarch64 = 1;
+
+ env->pc = addr;
+ cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}