diff options
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r-- | arch/x86/kvm/mmu.c | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index fbb04aee8301..4ab04de5a76a 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -18,9 +18,11 @@ | |||
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include "irq.h" | ||
21 | #include "mmu.h" | 22 | #include "mmu.h" |
22 | #include "x86.h" | 23 | #include "x86.h" |
23 | #include "kvm_cache_regs.h" | 24 | #include "kvm_cache_regs.h" |
25 | #include "x86.h" | ||
24 | 26 | ||
25 | #include <linux/kvm_host.h> | 27 | #include <linux/kvm_host.h> |
26 | #include <linux/types.h> | 28 | #include <linux/types.h> |
@@ -2587,6 +2589,50 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, | |||
2587 | error_code & PFERR_WRITE_MASK, gfn); | 2589 | error_code & PFERR_WRITE_MASK, gfn); |
2588 | } | 2590 | } |
2589 | 2591 | ||
2592 | int kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn) | ||
2593 | { | ||
2594 | struct kvm_arch_async_pf arch; | ||
2595 | arch.gfn = gfn; | ||
2596 | |||
2597 | return kvm_setup_async_pf(vcpu, gva, gfn, &arch); | ||
2598 | } | ||
2599 | |||
2600 | static bool can_do_async_pf(struct kvm_vcpu *vcpu) | ||
2601 | { | ||
2602 | if (unlikely(!irqchip_in_kernel(vcpu->kvm) || | ||
2603 | kvm_event_needs_reinjection(vcpu))) | ||
2604 | return false; | ||
2605 | |||
2606 | return kvm_x86_ops->interrupt_allowed(vcpu); | ||
2607 | } | ||
2608 | |||
2609 | static bool try_async_pf(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva, | ||
2610 | pfn_t *pfn) | ||
2611 | { | ||
2612 | bool async; | ||
2613 | |||
2614 | *pfn = gfn_to_pfn_async(vcpu->kvm, gfn, &async); | ||
2615 | |||
2616 | if (!async) | ||
2617 | return false; /* *pfn has correct page already */ | ||
2618 | |||
2619 | put_page(pfn_to_page(*pfn)); | ||
2620 | |||
2621 | if (can_do_async_pf(vcpu)) { | ||
2622 | trace_kvm_try_async_get_page(async, *pfn); | ||
2623 | if (kvm_find_async_pf_gfn(vcpu, gfn)) { | ||
2624 | trace_kvm_async_pf_doublefault(gva, gfn); | ||
2625 | kvm_make_request(KVM_REQ_APF_HALT, vcpu); | ||
2626 | return true; | ||
2627 | } else if (kvm_arch_setup_async_pf(vcpu, gva, gfn)) | ||
2628 | return true; | ||
2629 | } | ||
2630 | |||
2631 | *pfn = gfn_to_pfn(vcpu->kvm, gfn); | ||
2632 | |||
2633 | return false; | ||
2634 | } | ||
2635 | |||
2590 | static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, | 2636 | static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, |
2591 | u32 error_code) | 2637 | u32 error_code) |
2592 | { | 2638 | { |
@@ -2609,7 +2655,11 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, | |||
2609 | 2655 | ||
2610 | mmu_seq = vcpu->kvm->mmu_notifier_seq; | 2656 | mmu_seq = vcpu->kvm->mmu_notifier_seq; |
2611 | smp_rmb(); | 2657 | smp_rmb(); |
2612 | pfn = gfn_to_pfn(vcpu->kvm, gfn); | 2658 | |
2659 | if (try_async_pf(vcpu, gfn, gpa, &pfn)) | ||
2660 | return 0; | ||
2661 | |||
2662 | /* mmio */ | ||
2613 | if (is_error_pfn(pfn)) | 2663 | if (is_error_pfn(pfn)) |
2614 | return kvm_handle_bad_page(vcpu->kvm, gfn, pfn); | 2664 | return kvm_handle_bad_page(vcpu->kvm, gfn, pfn); |
2615 | spin_lock(&vcpu->kvm->mmu_lock); | 2665 | spin_lock(&vcpu->kvm->mmu_lock); |