KVM: x86: detect LVTT changes under APICv
authorRadim Krčmář <rkrcmar@redhat.com>
Thu, 30 Oct 2014 14:06:46 +0000 (15:06 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 3 Nov 2014 11:07:32 +0000 (12:07 +0100)
APIC-write VM exits are "trap-like": they save CS:RIP values for the
instruction after the write, and more importantly, the handler will
already see the new value in the virtual-APIC page.  This means that
apic_reg_write cannot use kvm_apic_get_reg to omit timer cancelation
when mode changes.

timer_mode_mask shouldn't be changing as it depends on cpuid.

Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h

index 80df439d40861496f585fd8b9a485662948289d3..fa3c6f7fdca448c5f4465c4a1c205c297cc34d66 100644 (file)
@@ -1242,17 +1242,20 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
                break;
 
-       case APIC_LVTT:
-               if ((kvm_apic_get_reg(apic, APIC_LVTT) &
-                   apic->lapic_timer.timer_mode_mask) !=
-                  (val & apic->lapic_timer.timer_mode_mask))
+       case APIC_LVTT: {
+               u32 timer_mode = val & apic->lapic_timer.timer_mode_mask;
+
+               if (apic->lapic_timer.timer_mode != timer_mode) {
+                       apic->lapic_timer.timer_mode = timer_mode;
                        hrtimer_cancel(&apic->lapic_timer.timer);
+               }
 
                if (!kvm_apic_sw_enabled(apic))
                        val |= APIC_LVT_MASKED;
                val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask);
                apic_set_reg(apic, APIC_LVTT, val);
                break;
+       }
 
        case APIC_TMICT:
                if (apic_lvtt_tscdeadline(apic))
@@ -1483,6 +1486,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
 
        for (i = 0; i < APIC_LVT_NUM; i++)
                apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
+       apic->lapic_timer.timer_mode = 0;
        apic_set_reg(apic, APIC_LVT0,
                     SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
 
index 87e0fae1f4c66f9e068ed1119c9ac96495b8b305..35d83dcae8f9da047cec694eeb3dd71f73bc51d4 100644 (file)
@@ -11,6 +11,7 @@
 struct kvm_timer {
        struct hrtimer timer;
        s64 period;                             /* unit: ns */
+       u32 timer_mode;
        u32 timer_mode_mask;
        u64 tscdeadline;
        atomic_t pending;                       /* accumulated triggered timers */