KVM: async_pf: Let guest support delivery of async_pf from guest mode
authorWanpeng Li <wanpeng.li@hotmail.com>
Fri, 14 Jul 2017 01:30:42 +0000 (18:30 -0700)
committerRadim Krčmář <rkrcmar@redhat.com>
Fri, 14 Jul 2017 12:26:16 +0000 (14:26 +0200)
Adds another flag bit (bit 2) to MSR_KVM_ASYNC_PF_EN. If bit 2 is 1,
async page faults are delivered to L1 as #PF vmexits; if bit 2 is 0,
kvm_can_do_async_pf returns 0 if in guest mode.

This is similar to what svm.c wanted to do all along, but it is only
enabled for Linux as L1 hypervisor.  Foreign hypervisors must never
receive async page faults as vmexits, because they'd probably be very
confused about that.

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
Documentation/virtual/kvm/msr.txt
arch/x86/include/asm/kvm_host.h
arch/x86/include/uapi/asm/kvm_para.h
arch/x86/kernel/kvm.c
arch/x86/kvm/mmu.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c

index 0a9ea515512a208a4b239813028c136e1d2943af..1ebecc115dc6efdbbfa76eb4ab329f5b1d8b765e 100644 (file)
@@ -166,10 +166,11 @@ MSR_KVM_SYSTEM_TIME: 0x12
 MSR_KVM_ASYNC_PF_EN: 0x4b564d02
        data: Bits 63-6 hold 64-byte aligned physical address of a
        64 byte memory area which must be in guest RAM and must be
-       zeroed. Bits 5-2 are reserved and should be zero. Bit 0 is 1
+       zeroed. Bits 5-3 are reserved and should be zero. Bit 0 is 1
        when asynchronous page faults are enabled on the vcpu 0 when
        disabled. Bit 1 is 1 if asynchronous page faults can be injected
-       when vcpu is in cpl == 0.
+       when vcpu is in cpl == 0. Bit 2 is 1 if asynchronous page faults
+       are delivered to L1 as #PF vmexits.
 
        First 4 byte of 64 byte memory location will be written to by
        the hypervisor at the time of asynchronous page fault (APF)
index 5e9ac508f718929c663bc3b9cf5b854287cdb71c..da3261e384d3a19d15560b26d0b11a7064e1cc19 100644 (file)
@@ -653,6 +653,7 @@ struct kvm_vcpu_arch {
                bool send_user_only;
                u32 host_apf_reason;
                unsigned long nested_apf_token;
+               bool delivery_as_pf_vmexit;
        } apf;
 
        /* OSVW MSRs (AMD only) */
index cff0bb6556f8809ec39d08c61036a86d7c8adde0..a965e5b0d32804fa19f9434600054b39014dd310 100644 (file)
@@ -67,6 +67,7 @@ struct kvm_clock_pairing {
 
 #define KVM_ASYNC_PF_ENABLED                   (1 << 0)
 #define KVM_ASYNC_PF_SEND_ALWAYS               (1 << 1)
+#define KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT     (1 << 2)
 
 /* Operations for KVM_HC_MMU_OP */
 #define KVM_MMU_OP_WRITE_PTE            1
index 43e10d6fdbeda3002dcd9e2063a723ded4ca5972..71c17a5be983524ea277718b759ff1511a9a3214 100644 (file)
@@ -330,7 +330,12 @@ static void kvm_guest_cpu_init(void)
 #ifdef CONFIG_PREEMPT
                pa |= KVM_ASYNC_PF_SEND_ALWAYS;
 #endif
-               wrmsrl(MSR_KVM_ASYNC_PF_EN, pa | KVM_ASYNC_PF_ENABLED);
+               pa |= KVM_ASYNC_PF_ENABLED;
+
+               /* Async page fault support for L1 hypervisor is optional */
+               if (wrmsr_safe(MSR_KVM_ASYNC_PF_EN,
+                       (pa | KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT) & 0xffffffff, pa >> 32) < 0)
+                       wrmsrl(MSR_KVM_ASYNC_PF_EN, pa);
                __this_cpu_write(apf_reason.enabled, 1);
                printk(KERN_INFO"KVM setup async PF for cpu %d\n",
                       smp_processor_id());
index 3825a35cd7524e38235d40eeb19db230892f19b4..9b1dd114956a8bcb9e724bd4df792460f68a0943 100644 (file)
@@ -3749,7 +3749,7 @@ bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)
                     kvm_event_needs_reinjection(vcpu)))
                return false;
 
-       if (is_guest_mode(vcpu))
+       if (!vcpu->arch.apf.delivery_as_pf_vmexit && is_guest_mode(vcpu))
                return false;
 
        return kvm_x86_ops->interrupt_allowed(vcpu);
index 5a3bb1a697a226e68874c5a2a49a57c946822be3..84e62acf2dd861023b17382e61f9c98c8df82f68 100644 (file)
@@ -8037,7 +8037,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
                if (is_nmi(intr_info))
                        return false;
                else if (is_page_fault(intr_info))
-                       return enable_ept;
+                       return !vmx->vcpu.arch.apf.host_apf_reason && enable_ept;
                else if (is_no_device(intr_info) &&
                         !(vmcs12->guest_cr0 & X86_CR0_TS))
                        return false;
index f3f10154c1339723cea0ce29bde25fa90550c4f9..6753f09827914a83946e20f012ca7e17cce446e7 100644 (file)
@@ -2063,8 +2063,8 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
 {
        gpa_t gpa = data & ~0x3f;
 
-       /* Bits 2:5 are reserved, Should be zero */
-       if (data & 0x3c)
+       /* Bits 3:5 are reserved, Should be zero */
+       if (data & 0x38)
                return 1;
 
        vcpu->arch.apf.msr_val = data;
@@ -2080,6 +2080,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
                return 1;
 
        vcpu->arch.apf.send_user_only = !(data & KVM_ASYNC_PF_SEND_ALWAYS);
+       vcpu->arch.apf.delivery_as_pf_vmexit = data & KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT;
        kvm_async_pf_wakeup_all(vcpu);
        return 0;
 }