kvm, arm: Don't forward IRQ/FIQ when using the kernel's GIC
authorAndreas Sandberg <andreas.sandberg@arm.com>
Mon, 24 Apr 2017 16:38:46 +0000 (16:38 +0000)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Fri, 7 Jul 2017 10:11:16 +0000 (10:11 +0000)
The BaseArmKvmCPU is responsible for forwarding the IRQ and FIQ
signals from gem5's simulated GIC to KVM. However, these signals
shouldn't be used when the in-kernel GIC emulator is used.

Instead of delivering the interrupts to the guest, we should just
ignore them since any such pending interrupts are likely to be an
artifact of CPU switching or incorrect draining.

Change-Id: I083b72639384272157f92f44a6606bdf0be7413c
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Sudhanshu Jha <sudhanshu.jha@arm.com>
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/3660

src/arch/arm/kvm/base_cpu.cc
src/arch/arm/kvm/gic.cc
src/cpu/kvm/vm.hh

index e25112cae70e5a6a59f641b3815642d5e345580d..765965092d4b553d278900384eee15655a646dcd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015 ARM Limited
+ * Copyright (c) 2012, 2015, 2017 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -88,20 +88,31 @@ BaseArmKvmCPU::startup()
 Tick
 BaseArmKvmCPU::kvmRun(Tick ticks)
 {
-    bool simFIQ(interrupts[0]->checkRaw(INT_FIQ));
-    bool simIRQ(interrupts[0]->checkRaw(INT_IRQ));
+    const bool simFIQ(interrupts[0]->checkRaw(INT_FIQ));
+    const bool simIRQ(interrupts[0]->checkRaw(INT_IRQ));
 
-    if (fiqAsserted != simFIQ) {
-        fiqAsserted = simFIQ;
-        DPRINTF(KvmInt, "KVM: Update FIQ state: %i\n", simFIQ);
-        vm.setIRQLine(INTERRUPT_VCPU_FIQ(vcpuID), simFIQ);
-    }
-    if (irqAsserted != simIRQ) {
-        irqAsserted = simIRQ;
-        DPRINTF(KvmInt, "KVM: Update IRQ state: %i\n", simIRQ);
-        vm.setIRQLine(INTERRUPT_VCPU_IRQ(vcpuID), simIRQ);
+    if (!vm.hasKernelIRQChip()) {
+        if (fiqAsserted != simFIQ) {
+            DPRINTF(KvmInt, "KVM: Update FIQ state: %i\n", simFIQ);
+            vm.setIRQLine(INTERRUPT_VCPU_FIQ(vcpuID), simFIQ);
+        }
+        if (irqAsserted != simIRQ) {
+            DPRINTF(KvmInt, "KVM: Update IRQ state: %i\n", simIRQ);
+            vm.setIRQLine(INTERRUPT_VCPU_IRQ(vcpuID), simIRQ);
+        }
+    } else {
+        warn_if(simFIQ && !fiqAsserted,
+                "FIQ raised by the simulated interrupt controller " \
+                "despite in-kernel GIC emulation. This is probably a bug.");
+
+        warn_if(simIRQ && !irqAsserted,
+                "IRQ raised by the simulated interrupt controller " \
+                "despite in-kernel GIC emulation. This is probably a bug.");
     }
 
+    irqAsserted = simIRQ;
+    fiqAsserted = simFIQ;
+
     return BaseKvmCPU::kvmRun(ticks);
 }
 
index 498b79faacef203efe4da56d30ac991ee501db53..ce3baa5588f127459ec45a66558c66580a638559 100644 (file)
@@ -54,6 +54,10 @@ KvmKernelGicV2::KvmKernelGicV2(KvmVM &_vm, Addr cpu_addr, Addr dist_addr,
       vm(_vm),
       kdev(vm.createDevice(KVM_DEV_TYPE_ARM_VGIC_V2))
 {
+    // Tell the VM that we will emulate the GIC in the kernel. This
+    // disables IRQ and FIQ handling in the KVM CPU model.
+    vm.enableKernelIRQChip();
+
     kdev.setAttr<uint64_t>(
         KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, dist_addr);
     kdev.setAttr<uint64_t>(
index df2e4119a04450b5613fb95745358df393a58976..e122bbf86fc7a25b49aa89fead75253abc7ea5f4 100644 (file)
@@ -351,6 +351,15 @@ class KvmVM : public SimObject
      * Is in-kernel IRQ chip emulation enabled?
      */
     bool hasKernelIRQChip() const { return _hasKernelIRQChip; }
+
+    /**
+     * Tell the VM and VCPUs to use an in-kernel IRQ chip for
+     * interrupt delivery.
+     *
+     * @note This is set automatically if the IRQ chip is created
+     * using the KvmVM::createIRQChip() API.
+     */
+    void enableKernelIRQChip() { _hasKernelIRQChip = true; }
     /** @} */
 
     struct MemSlot