#include "qom/cpu.h"
#include "qemu/log.h"
#include "trace.h"
+#include "sysemu/kvm.h"
/* #define DEBUG_GIC */
return;
}
+ if (kvm_enabled() && !kvm_arm_supports_user_irq()) {
+ error_setg(errp, "KVM with user space irqchip only works when the "
+ "host kernel supports KVM_CAP_ARM_USER_IRQ");
+ return;
+ }
+
/* This creates distributor and main CPU interface (s->cpuiomem[0]) */
gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops);
int kvm_cpu_exec(CPUState *cpu);
int kvm_destroy_vcpu(CPUState *cpu);
+/**
+ * kvm_arm_supports_user_irq
+ *
+ * Not all KVM implementations support notifications for kernel generated
+ * interrupt events to user space. This function indicates whether the current
+ * KVM implementation does support them.
+ *
+ * Returns: true if KVM supports using kernel generated IRQs from user space
+ */
+bool kvm_arm_supports_user_irq(void);
+
#ifdef NEED_CPU_H
#include "cpu.h"
*/
kvm_async_interrupts_allowed = true;
+ /*
+ * PSCI wakes up secondary cores, so we always need to
+ * have vCPUs waiting in kernel space
+ */
+ kvm_halt_in_kernel_allowed = true;
+
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
type_register_static(&host_arm_cpu_type_info);
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
{
+ ARMCPU *cpu;
+ uint32_t switched_level;
+
+ if (kvm_irqchip_in_kernel()) {
+ /*
+ * We only need to sync timer states with user-space interrupt
+ * controllers, so return early and save cycles if we don't.
+ */
+ return MEMTXATTRS_UNSPECIFIED;
+ }
+
+ cpu = ARM_CPU(cs);
+
+ /* Synchronize our shadowed in-kernel device irq lines with the kvm ones */
+ if (run->s.regs.device_irq_level != cpu->device_irq_level) {
+ switched_level = cpu->device_irq_level ^ run->s.regs.device_irq_level;
+
+ qemu_mutex_lock_iothread();
+
+ if (switched_level & KVM_ARM_DEV_EL1_VTIMER) {
+ qemu_set_irq(cpu->gt_timer_outputs[GTIMER_VIRT],
+ !!(run->s.regs.device_irq_level &
+ KVM_ARM_DEV_EL1_VTIMER));
+ switched_level &= ~KVM_ARM_DEV_EL1_VTIMER;
+ }
+
+ if (switched_level & KVM_ARM_DEV_EL1_PTIMER) {
+ qemu_set_irq(cpu->gt_timer_outputs[GTIMER_PHYS],
+ !!(run->s.regs.device_irq_level &
+ KVM_ARM_DEV_EL1_PTIMER));
+ switched_level &= ~KVM_ARM_DEV_EL1_PTIMER;
+ }
+
+ /* XXX PMU IRQ is missing */
+
+ if (switched_level) {
+ qemu_log_mask(LOG_UNIMP, "%s: unhandled in-kernel device IRQ %x\n",
+ __func__, switched_level);
+ }
+
+ /* We also mark unknown levels as processed to not waste cycles */
+ cpu->device_irq_level = run->s.regs.device_irq_level;
+ qemu_mutex_unlock_iothread();
+ }
+
return MEMTXATTRS_UNSPECIFIED;
}