aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVitaly Kuznetsov <vkuznets@redhat.com>2018-08-02 11:08:16 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2018-09-19 18:26:43 -0400
commitd1766202779e81d0f2a94c4650a6ba31497d369d (patch)
treeedd4176bdcdefd4634921af43f3f7af499b16dff
parent1795f81f6167bd57b37459789f1f05ab61ace896 (diff)
x86/kvm/lapic: always disable MMIO interface in x2APIC mode
When VMX is used with flexpriority disabled (because of no support or if disabled with module parameter) MMIO interface to lAPIC is still available in x2APIC mode while it shouldn't be (kvm-unit-tests): PASS: apic_disable: Local apic enabled in x2APIC mode PASS: apic_disable: CPUID.1H:EDX.APIC[bit 9] is set FAIL: apic_disable: *0xfee00030: 50014 The issue appears because we basically do nothing while switching to x2APIC mode when APIC access page is not used. apic_mmio_{read,write} only check if lAPIC is disabled before proceeding to actual write. When APIC access is virtualized we correctly manipulate with VMX controls in vmx_set_virtual_apic_mode() and we don't get vmexits from memory writes in x2APIC mode so there's no issue. Disabling MMIO interface seems to be easy. The question is: what do we do with these reads and writes? If we add apic_x2apic_mode() check to apic_mmio_in_range() and return -EOPNOTSUPP these reads and writes will go to userspace. When lAPIC is in kernel, Qemu uses this interface to inject MSIs only (see kvm_apic_mem_write() in hw/i386/kvm/apic.c). This somehow works with disabled lAPIC but when we're in xAPIC mode we will get a real injected MSI from every write to lAPIC. Not good. The simplest solution seems to be to just ignore writes to the region and return ~0 for all reads when we're in x2APIC mode. This is what this patch does. However, this approach is inconsistent with what currently happens when flexpriority is enabled: we allocate APIC access page and create KVM memory region so in x2APIC modes all reads and writes go to this pre-allocated page which is, btw, the same for all vCPUs. Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--arch/x86/include/uapi/asm/kvm.h1
-rw-r--r--arch/x86/kvm/lapic.c22
2 files changed, 20 insertions, 3 deletions
diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
index 86299efa804a..fd23d5778ea1 100644
--- a/arch/x86/include/uapi/asm/kvm.h
+++ b/arch/x86/include/uapi/asm/kvm.h
@@ -377,6 +377,7 @@ struct kvm_sync_regs {
377 377
378#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0) 378#define KVM_X86_QUIRK_LINT0_REENABLED (1 << 0)
379#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1) 379#define KVM_X86_QUIRK_CD_NW_CLEARED (1 << 1)
380#define KVM_X86_QUIRK_LAPIC_MMIO_HOLE (1 << 2)
380 381
381#define KVM_STATE_NESTED_GUEST_MODE 0x00000001 382#define KVM_STATE_NESTED_GUEST_MODE 0x00000001
382#define KVM_STATE_NESTED_RUN_PENDING 0x00000002 383#define KVM_STATE_NESTED_RUN_PENDING 0x00000002
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 17c0472c5b34..fbb0e6df121b 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1344,9 +1344,8 @@ EXPORT_SYMBOL_GPL(kvm_lapic_reg_read);
1344 1344
1345static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr) 1345static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr)
1346{ 1346{
1347 return kvm_apic_hw_enabled(apic) && 1347 return addr >= apic->base_address &&
1348 addr >= apic->base_address && 1348 addr < apic->base_address + LAPIC_MMIO_LENGTH;
1349 addr < apic->base_address + LAPIC_MMIO_LENGTH;
1350} 1349}
1351 1350
1352static int apic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this, 1351static int apic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
@@ -1358,6 +1357,15 @@ static int apic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
1358 if (!apic_mmio_in_range(apic, address)) 1357 if (!apic_mmio_in_range(apic, address))
1359 return -EOPNOTSUPP; 1358 return -EOPNOTSUPP;
1360 1359
1360 if (!kvm_apic_hw_enabled(apic) || apic_x2apic_mode(apic)) {
1361 if (!kvm_check_has_quirk(vcpu->kvm,
1362 KVM_X86_QUIRK_LAPIC_MMIO_HOLE))
1363 return -EOPNOTSUPP;
1364
1365 memset(data, 0xff, len);
1366 return 0;
1367 }
1368
1361 kvm_lapic_reg_read(apic, offset, len, data); 1369 kvm_lapic_reg_read(apic, offset, len, data);
1362 1370
1363 return 0; 1371 return 0;
@@ -1917,6 +1925,14 @@ static int apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
1917 if (!apic_mmio_in_range(apic, address)) 1925 if (!apic_mmio_in_range(apic, address))
1918 return -EOPNOTSUPP; 1926 return -EOPNOTSUPP;
1919 1927
1928 if (!kvm_apic_hw_enabled(apic) || apic_x2apic_mode(apic)) {
1929 if (!kvm_check_has_quirk(vcpu->kvm,
1930 KVM_X86_QUIRK_LAPIC_MMIO_HOLE))
1931 return -EOPNOTSUPP;
1932
1933 return 0;
1934 }
1935
1920 /* 1936 /*
1921 * APIC register must be aligned on 128-bits boundary. 1937 * APIC register must be aligned on 128-bits boundary.
1922 * 32/64/128 bits registers must be accessed thru 32 bits. 1938 * 32/64/128 bits registers must be accessed thru 32 bits.