KVM: arm/arm64: Don’t emulate virtual timers on userspace ioctls [Linux 5.1]

KVM: arm/arm64: Don’t emulate virtual timers on userspace ioctls [Linux 5.1]

This Linux kernel change "KVM: arm/arm64: Don’t emulate virtual timers on userspace ioctls" is included in the Linux 5.1 release. This change is authored by Christoffer Dall <christoffer.dall [at] arm.com> on Thu Apr 25 13:57:40 2019 +0100. The commit for this change in Linux stable tree is 6bc2100 (patch).

KVM: arm/arm64: Don't emulate virtual timers on userspace ioctls

When a VCPU never runs before a guest exists, but we set timer registers
up via ioctls, the associated hrtimer might never get cancelled.

Since we moved vcpu_load/put into the arch-specific implementations and
only have load/put for KVM_RUN, we won't ever have a scheduled hrtimer
for emulating a timer when modifying the timer state via an ioctl from
user space.  All we need to do is make sure that we pick up the right
state when we load the timer state next time userspace calls KVM_RUN
again.

We also do not need to worry about this interacting with the bg_timer,
because if we were in WFI from the guest, and somehow ended up in a
kvm_arm_timer_set_reg, it means that:

 1. the VCPU thread has received a signal,
 2. we have called vcpu_load when being scheduled in again,
 3. we have called vcpu_put when we returned to userspace for it to issue
    another ioctl

And therefore will not have a bg_timer programmed and the event is
treated as a spurious wakeup from WFI if userspace decides to run the
vcpu again even if there are not virtual interrupts.

This fixes stray virtual timer interrupts triggered by an expiring
hrtimer, which happens after a failed live migration, for instance.

Fixes: bee038a674875 ("KVM: arm/arm64: Rework the timer code to use a timer_map")
Signed-off-by: Christoffer Dall <[email protected]>
Reported-by: Andre Przywara <[email protected]>
Tested-by: Andre Przywara <[email protected]>
Signed-off-by: Andre Przywara <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>

There are 13 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 virt/kvm/arm/arch_timer.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index d43308d..7fc272e 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -508,6 +508,14 @@ static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
    struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);

    /*
+    * Update the timer output so that it is likely to match the
+    * state we're about to restore. If the timer expires between
+    * this point and the register restoration, we'll take the
+    * interrupt anyway.
+    */
+   kvm_timer_update_irq(vcpu, kvm_timer_should_fire(vtimer), vtimer);
+
+   /*
     * When using a userspace irqchip with the architected timers and a
     * host interrupt controller that doesn't support an active state, we
     * must still prevent continuously exiting from the guest, and
@@ -730,7 +738,6 @@ static void kvm_timer_init_interrupt(void *info)
 int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
 {
    struct arch_timer_context *timer;
-   bool level;

    switch (regid) {
    case KVM_REG_ARM_TIMER_CTL:
@@ -758,10 +765,6 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
        return -1;
    }

-   level = kvm_timer_should_fire(timer);
-   kvm_timer_update_irq(vcpu, level, timer);
-   timer_emulate(timer);
-
    return 0;
 }

Leave a Reply

Your email address will not be published. Required fields are marked *