diff options
author | Radim Krčmář <rkrcmar@redhat.com> | 2014-10-30 10:06:46 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-11-03 06:07:32 -0500 |
commit | a323b409820c8afd33fbd841f5534eb84b406e8d (patch) | |
tree | 9bc876d1347bf88e0b8b5be0c6d7ab79c998163a /arch/x86/kvm/lapic.c | |
parent | e462755cae2bf8297a663278935ad4d59812d2f3 (diff) |
KVM: x86: detect LVTT changes under APICv
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>
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r-- | arch/x86/kvm/lapic.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 80df439d4086..fa3c6f7fdca4 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -1242,17 +1242,20 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) | |||
1242 | 1242 | ||
1243 | break; | 1243 | break; |
1244 | 1244 | ||
1245 | case APIC_LVTT: | 1245 | case APIC_LVTT: { |
1246 | if ((kvm_apic_get_reg(apic, APIC_LVTT) & | 1246 | u32 timer_mode = val & apic->lapic_timer.timer_mode_mask; |
1247 | apic->lapic_timer.timer_mode_mask) != | 1247 | |
1248 | (val & apic->lapic_timer.timer_mode_mask)) | 1248 | if (apic->lapic_timer.timer_mode != timer_mode) { |
1249 | apic->lapic_timer.timer_mode = timer_mode; | ||
1249 | hrtimer_cancel(&apic->lapic_timer.timer); | 1250 | hrtimer_cancel(&apic->lapic_timer.timer); |
1251 | } | ||
1250 | 1252 | ||
1251 | if (!kvm_apic_sw_enabled(apic)) | 1253 | if (!kvm_apic_sw_enabled(apic)) |
1252 | val |= APIC_LVT_MASKED; | 1254 | val |= APIC_LVT_MASKED; |
1253 | val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask); | 1255 | val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask); |
1254 | apic_set_reg(apic, APIC_LVTT, val); | 1256 | apic_set_reg(apic, APIC_LVTT, val); |
1255 | break; | 1257 | break; |
1258 | } | ||
1256 | 1259 | ||
1257 | case APIC_TMICT: | 1260 | case APIC_TMICT: |
1258 | if (apic_lvtt_tscdeadline(apic)) | 1261 | if (apic_lvtt_tscdeadline(apic)) |
@@ -1483,6 +1486,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) | |||
1483 | 1486 | ||
1484 | for (i = 0; i < APIC_LVT_NUM; i++) | 1487 | for (i = 0; i < APIC_LVT_NUM; i++) |
1485 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); | 1488 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); |
1489 | apic->lapic_timer.timer_mode = 0; | ||
1486 | apic_set_reg(apic, APIC_LVT0, | 1490 | apic_set_reg(apic, APIC_LVT0, |
1487 | SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); | 1491 | SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); |
1488 | 1492 | ||