From: Wanpeng Li <wanpeng...@hotmail.com>

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.

Cc: Paolo Bonzini <pbonz...@redhat.com>
Cc: Radim Krčmář <rkrc...@redhat.com>
Signed-off-by: Wanpeng Li <wanpeng...@hotmail.com>
---
 Documentation/virtual/kvm/msr.txt    | 5 +++--
 arch/x86/include/asm/kvm_host.h      | 1 +
 arch/x86/include/uapi/asm/kvm_para.h | 1 +
 arch/x86/kernel/kvm.c                | 7 ++++++-
 arch/x86/kvm/mmu.c                   | 2 +-
 arch/x86/kvm/vmx.c                   | 2 +-
 arch/x86/kvm/x86.c                   | 5 +++--
 7 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/Documentation/virtual/kvm/msr.txt 
b/Documentation/virtual/kvm/msr.txt
index 0a9ea51..1ebecc1 100644
--- a/Documentation/virtual/kvm/msr.txt
+++ b/Documentation/virtual/kvm/msr.txt
@@ -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)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 71aef4b..a981ab8 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -648,6 +648,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) */
diff --git a/arch/x86/include/uapi/asm/kvm_para.h 
b/arch/x86/include/uapi/asm/kvm_para.h
index cff0bb6..a965e5b 100644
--- a/arch/x86/include/uapi/asm/kvm_para.h
+++ b/arch/x86/include/uapi/asm/kvm_para.h
@@ -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
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 43e10d6..71c17a5 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -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());
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 4a7dc00..fb8c35f 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3705,7 +3705,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);
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 8724ea6..4f616db 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -8001,7 +8001,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;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2a4520f..fdeeb66 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2065,8 +2065,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;
@@ -2082,6 +2082,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;
 }
-- 
2.7.4

Reply via email to