@@ -365,6 +365,8 @@ struct kvm_vcpu_arch {
unsigned long singlestep_rip;
/* fields used by HYPER-V emulation */
u64 hv_vapic;
+
+ ktime_t latest_userspace_exit_time;
};
struct kvm_mem_alias {
@@ -4339,6 +4339,20 @@ out:
return r;
}
+#ifdef CONFIG_KVM_MMIO
+
+#define KVM_USERSPACE_MMIO_MAX_INTERVAL (NSEC_PER_SEC / 25)
+static bool mmio_need_exit_to_userspace(struct kvm_vcpu *vcpu)
+{
+ ktime_t gap, now = ktime_get();
+
+ gap = ktime_sub(now, vcpu->arch.latest_userspace_exit_time);
+ if (ktime_to_ns(gap) > KVM_USERSPACE_MMIO_MAX_INTERVAL)
+ return true;
+
+ return false;
+}
+#endif
static int __vcpu_run(struct kvm_vcpu *vcpu)
{
@@ -4404,6 +4418,10 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
kvm_resched(vcpu);
vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
}
+#ifdef CONFIG_KVM_MMIO
+ if (mmio_need_exit_to_userspace(vcpu))
+ r = 0;
+#endif
}
srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
@@ -4463,6 +4481,16 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
r = __vcpu_run(vcpu);
+#ifdef CONFIG_KVM_MMIO
+ if (mmio_need_exit_to_userspace(vcpu)) {
+ /* Use KVM_EXIT_IRQ_WINDOW_OPEN because userspace would do
+ * nothing to handle it */
+ kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
+ r = 0;
+ }
+ vcpu->arch.latest_userspace_exit_time = ktime_get();
+#endif
+
out:
if (vcpu->sigset_active)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
@@ -5455,6 +5483,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
goto fail_mmu_destroy;
}
vcpu->arch.mcg_cap = KVM_MAX_MCE_BANKS;
+#ifdef CONFIG_KVM_MMIO
+ vcpu->arch.latest_userspace_exit_time = ktime_get();
+#endif
return 0;