#include "arch/arm/interrupts.hh"
#include "debug/KvmInt.hh"
+#include "dev/arm/generic_timer.hh"
#include "params/BaseArmKvmCPU.hh"
+#include "params/GenericTimer.hh"
#define INTERRUPT_ID(type, vcpu, irq) ( \
((type) << KVM_ARM_IRQ_TYPE_SHIFT) | \
BaseArmKvmCPU::BaseArmKvmCPU(BaseArmKvmCPUParams *params)
: BaseKvmCPU(params),
- irqAsserted(false), fiqAsserted(false)
+ irqAsserted(false), fiqAsserted(false),
+ virtTimerPin(nullptr), prevDeviceIRQLevel(0)
{
}
target_config.features[0] |= (1 << KVM_ARM_VCPU_EL1_32BIT);
}
kvmArmVCpuInit(target_config);
+
+ if (!vm.hasKernelIRQChip())
+ virtTimerPin = static_cast<ArmSystem *>(system)\
+ ->getGenericTimer()->params()->int_virt->get(tc);
}
Tick
irqAsserted = simIRQ;
fiqAsserted = simFIQ;
- return BaseKvmCPU::kvmRun(ticks);
+ Tick kvmRunTicks = BaseKvmCPU::kvmRun(ticks);
+
+ if (!vm.hasKernelIRQChip()) {
+ uint64_t device_irq_level =
+ getKvmRunState()->s.regs.device_irq_level;
+
+ if (!(prevDeviceIRQLevel & KVM_ARM_DEV_EL1_VTIMER) &&
+ (device_irq_level & KVM_ARM_DEV_EL1_VTIMER)) {
+
+ DPRINTF(KvmInt, "In-kernel vtimer IRQ asserted\n");
+ prevDeviceIRQLevel |= KVM_ARM_DEV_EL1_VTIMER;
+ virtTimerPin->raise();
+
+ } else if ((prevDeviceIRQLevel & KVM_ARM_DEV_EL1_VTIMER) &&
+ !(device_irq_level & KVM_ARM_DEV_EL1_VTIMER)) {
+
+ DPRINTF(KvmInt, "In-kernel vtimer IRQ disasserted\n");
+ prevDeviceIRQLevel &= ~KVM_ARM_DEV_EL1_VTIMER;
+ virtTimerPin->clear();
+ }
+ }
+
+ return kvmRunTicks;
}
const BaseArmKvmCPU::RegIndexVector &
#include <vector>
#include "cpu/kvm/base.hh"
+#include "dev/arm/base_gic.hh"
struct BaseArmKvmCPUParams;
/** Cached state of the FIQ line */
bool fiqAsserted;
+ /**
+ * If the user-space GIC and the kernel-space timer are used
+ * simultaneously, set up this interrupt pin to forward interrupt from
+ * the timer to the GIC when timer IRQ level change is intercepted.
+ */
+ ArmInterruptPin *virtTimerPin;
+
+ /**
+ * KVM records whether each in-kernel device IRQ is asserted or
+ * disasserted in the kvmRunState->s.regs.device_irq_level bit map,
+ * and guarantees at least one KVM exit when the level changes. We
+ * use only the KVM_ARM_DEV_EL1_VTIMER bit field currently to track
+ * the level of the in-kernel timer, and preserve the last level in
+ * this class member.
+ */
+ uint64_t prevDeviceIRQLevel;
+
protected:
typedef std::vector<uint64_t> RegIndexVector;