summary refs log tree commit diff stats
path: root/target-arm/cpu.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-09-30 11:02:06 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-09-30 11:02:06 +0100
commit29429c7244c73eefada3d0ec6dd30c5698782d08 (patch)
treeca318448a3a953a6897001a4e04cb97f566f1456 /target-arm/cpu.c
parent70d3a7a7b8340d9f671c5aec4c6dd174fee2ef8e (diff)
parent136e67e9b50b61fb03fedcea5c4fbe74cf44fdcc (diff)
downloadfocaccia-qemu-29429c7244c73eefada3d0ec6dd30c5698782d08.tar.gz
focaccia-qemu-29429c7244c73eefada3d0ec6dd30c5698782d08.zip
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140929' into staging
target-arm:
 * more EL2/EL3 preparation work
 * don't handle c15_cpar changes via tb_flush()
 * fix some unused function warnings in ARM devices
 * build the GDB XML for 32 bit CPUs into qemu-*-aarch64
 * implement guest breakpoint support

# gpg: Signature made Mon 29 Sep 2014 19:25:37 BST using RSA key ID 14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"

* remotes/pmaydell/tags/pull-target-arm-20140929:
  target-arm: Add support for VIRQ and VFIQ
  target-arm: Add IRQ and FIQ routing to EL2 and 3
  target-arm: A64: Emulate the SMC insn
  target-arm: Add a Hypervisor Trap exception type
  target-arm: A64: Emulate the HVC insn
  target-arm: A64: Correct updates to FAR and ESR on exceptions
  target-arm: Don't take interrupts targeting lower ELs
  target-arm: Break out exception masking to a separate func
  target-arm: A64: Refactor aarch64_cpu_do_interrupt
  target-arm: Add SCR_EL3
  target-arm: Add HCR_EL2
  target-arm: Don't handle c15_cpar changes via tb_flush()
  hw/input/tsc210x.c: Delete unused array tsc2101_rates
  hw/display/pxa2xx_lcd.c: Remove unused function pxa2xx_dma_rdst_set
  hw/intc/imx_avic.c: Remove unused function imx_avic_set_prio()
  hw/display/blizzard.c: Delete unused function blizzard_rgb2yuv
  configure: Build GDB XML for 32 bit ARM CPUs into qemu aarch64 binaries
  target-arm: Implement handling of breakpoint firing
  target-arm: Implement setting guest breakpoints

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-arm/cpu.c')
-rw-r--r--target-arm/cpu.c60
1 files changed, 39 insertions, 21 deletions
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 407f977742..8ab6d9532e 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -41,7 +41,9 @@ static void arm_cpu_set_pc(CPUState *cs, vaddr value)
 static bool arm_cpu_has_work(CPUState *cs)
 {
     return cs->interrupt_request &
-        (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB);
+        (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD
+         | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ
+         | CPU_INTERRUPT_EXITTB);
 }
 
 static void cp_reg_reset(gpointer key, gpointer value, gpointer opaque)
@@ -173,11 +175,6 @@ static void arm_cpu_reset(CPUState *s)
     set_float_detect_tininess(float_tininess_before_rounding,
                               &env->vfp.standard_fp_status);
     tlb_flush(s, 1);
-    /* Reset is a state change for some CPUARMState fields which we
-     * bake assumptions about into translated code, so we need to
-     * tb_flush().
-     */
-    tb_flush(env);
 
 #ifndef CONFIG_USER_ONLY
     if (kvm_enabled()) {
@@ -185,18 +182,17 @@ static void arm_cpu_reset(CPUState *s)
     }
 #endif
 
+    hw_breakpoint_update_all(cpu);
     hw_watchpoint_update_all(cpu);
 }
 
 bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
     CPUClass *cc = CPU_GET_CLASS(cs);
-    ARMCPU *cpu = ARM_CPU(cs);
-    CPUARMState *env = &cpu->env;
     bool ret = false;
 
     if (interrupt_request & CPU_INTERRUPT_FIQ
-        && !(env->daif & PSTATE_F)) {
+        && arm_excp_unmasked(cs, EXCP_FIQ)) {
         cs->exception_index = EXCP_FIQ;
         cc->do_interrupt(cs);
         ret = true;
@@ -211,12 +207,23 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
        We avoid this by disabling interrupts when
        pc contains a magic address.  */
     if (interrupt_request & CPU_INTERRUPT_HARD
-        && !(env->daif & PSTATE_I)
-        && (!IS_M(env) || env->regs[15] < 0xfffffff0)) {
+        && arm_excp_unmasked(cs, EXCP_IRQ)) {
         cs->exception_index = EXCP_IRQ;
         cc->do_interrupt(cs);
         ret = true;
     }
+    if (interrupt_request & CPU_INTERRUPT_VIRQ
+        && arm_excp_unmasked(cs, EXCP_VIRQ)) {
+        cs->exception_index = EXCP_VIRQ;
+        cc->do_interrupt(cs);
+        ret = true;
+    }
+    if (interrupt_request & CPU_INTERRUPT_VFIQ
+        && arm_excp_unmasked(cs, EXCP_VFIQ)) {
+        cs->exception_index = EXCP_VFIQ;
+        cc->do_interrupt(cs);
+        ret = true;
+    }
 
     return ret;
 }
@@ -225,21 +232,29 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 static void arm_cpu_set_irq(void *opaque, int irq, int level)
 {
     ARMCPU *cpu = opaque;
+    CPUARMState *env = &cpu->env;
     CPUState *cs = CPU(cpu);
+    static const int mask[] = {
+        [ARM_CPU_IRQ] = CPU_INTERRUPT_HARD,
+        [ARM_CPU_FIQ] = CPU_INTERRUPT_FIQ,
+        [ARM_CPU_VIRQ] = CPU_INTERRUPT_VIRQ,
+        [ARM_CPU_VFIQ] = CPU_INTERRUPT_VFIQ
+    };
 
     switch (irq) {
-    case ARM_CPU_IRQ:
-        if (level) {
-            cpu_interrupt(cs, CPU_INTERRUPT_HARD);
-        } else {
-            cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+    case ARM_CPU_VIRQ:
+    case ARM_CPU_VFIQ:
+        if (!arm_feature(env, ARM_FEATURE_EL2)) {
+            hw_error("%s: Virtual interrupt line %d with no EL2 support\n",
+                     __func__, irq);
         }
-        break;
+        /* fall through */
+    case ARM_CPU_IRQ:
     case ARM_CPU_FIQ:
         if (level) {
-            cpu_interrupt(cs, CPU_INTERRUPT_FIQ);
+            cpu_interrupt(cs, mask[irq]);
         } else {
-            cpu_reset_interrupt(cs, CPU_INTERRUPT_FIQ);
+            cpu_reset_interrupt(cs, mask[irq]);
         }
         break;
     default:
@@ -289,9 +304,12 @@ static void arm_cpu_initfn(Object *obj)
 #ifndef CONFIG_USER_ONLY
     /* Our inbound IRQ and FIQ lines */
     if (kvm_enabled()) {
-        qdev_init_gpio_in(DEVICE(cpu), arm_cpu_kvm_set_irq, 2);
+        /* VIRQ and VFIQ are unused with KVM but we add them to maintain
+         * the same interface as non-KVM CPUs.
+         */
+        qdev_init_gpio_in(DEVICE(cpu), arm_cpu_kvm_set_irq, 4);
     } else {
-        qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 2);
+        qdev_init_gpio_in(DEVICE(cpu), arm_cpu_set_irq, 4);
     }
 
     cpu->gt_timer[GTIMER_PHYS] = timer_new(QEMU_CLOCK_VIRTUAL, GTIMER_SCALE,