@@ -549,7 +549,7 @@ static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
*/
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
- int ret;
+ int ret, timer_ret;
sigset_t sigsaved;
if (unlikely(!kvm_vcpu_initialized(vcpu)))
@@ -588,7 +588,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
*/
preempt_disable();
kvm_pmu_flush_hwstate(vcpu);
- kvm_timer_flush_hwstate(vcpu);
+ timer_ret = kvm_timer_flush_hwstate(vcpu);
kvm_vgic_flush_hwstate(vcpu);
local_irq_disable();
@@ -596,7 +596,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
/*
* Re-check atomic conditions
*/
- if (signal_pending(current)) {
+ if (timer_ret || signal_pending(current)) {
ret = -EINTR;
run->exit_reason = KVM_EXIT_INTR;
}
@@ -659,13 +659,17 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
* interrupt line.
*/
kvm_pmu_sync_hwstate(vcpu);
- kvm_timer_sync_hwstate(vcpu);
+ timer_ret = kvm_timer_sync_hwstate(vcpu);
kvm_vgic_sync_hwstate(vcpu);
preempt_enable();
ret = handle_exit(vcpu, run, ret);
+ if (!ret & timer_ret) {
+ ret = -EINTR;
+ run->exit_reason = KVM_EXIT_INTR;
+ }
}
if (vcpu->sigset_active)
@@ -242,6 +242,19 @@ void kvm_timer_unschedule(struct kvm_vcpu *vcpu)
timer_disarm(timer);
}
+static int kvm_timer_update_user_irqchip(struct kvm_vcpu *vcpu)
+{
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+ struct kvm_sync_regs *regs = &vcpu->run->s.regs;
+
+ if (irqchip_in_kernel(vcpu->kvm))
+ return 0;
+
+ if (timer->irq.level != (regs->kernel_timer_pending & KVM_ARM_TIMER_VTIMER))
+ return 1;
+ return 0;
+}
+
/**
* kvm_timer_flush_hwstate - prepare to move the virt timer to the cpu
* @vcpu: The vcpu pointer
@@ -258,6 +271,11 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
if (kvm_timer_update_state(vcpu))
return;
+ if (!irqchip_in_kernel(vcpu->kvm)) {
+ /* do your masking here */
+ return kvm_timer_update_user_irqchip(vcpu);
+ }
+
/*
* If we enter the guest with the virtual input level to the VGIC
* asserted, then we have already told the VGIC what we need to, and
@@ -315,8 +333,10 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
*
* Check if the virtual timer has expired while we were running in the guest,
* and inject an interrupt if that was the case.
+ *
+ * Return 1 to force exit to userspace, 0 otherwise.
*/
-void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
+int kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
{
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -327,6 +347,8 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
* could have expired, update the timer state.
*/
kvm_timer_update_state(vcpu);
+
+ return kvm_timer_update_user_irqchip(vcpu);
}
int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,