diff options
Diffstat (limited to 'arch/x86/kvm/paging_tmpl.h')
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 86 |
1 files changed, 40 insertions, 46 deletions
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 92994100638b..15610285ebb6 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -497,6 +497,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
497 | shadow_walk_next(&it)) { | 497 | shadow_walk_next(&it)) { |
498 | gfn_t table_gfn; | 498 | gfn_t table_gfn; |
499 | 499 | ||
500 | clear_sp_write_flooding_count(it.sptep); | ||
500 | drop_large_spte(vcpu, it.sptep); | 501 | drop_large_spte(vcpu, it.sptep); |
501 | 502 | ||
502 | sp = NULL; | 503 | sp = NULL; |
@@ -522,6 +523,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
522 | shadow_walk_next(&it)) { | 523 | shadow_walk_next(&it)) { |
523 | gfn_t direct_gfn; | 524 | gfn_t direct_gfn; |
524 | 525 | ||
526 | clear_sp_write_flooding_count(it.sptep); | ||
525 | validate_direct_spte(vcpu, it.sptep, direct_access); | 527 | validate_direct_spte(vcpu, it.sptep, direct_access); |
526 | 528 | ||
527 | drop_large_spte(vcpu, it.sptep); | 529 | drop_large_spte(vcpu, it.sptep); |
@@ -536,6 +538,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
536 | link_shadow_page(it.sptep, sp); | 538 | link_shadow_page(it.sptep, sp); |
537 | } | 539 | } |
538 | 540 | ||
541 | clear_sp_write_flooding_count(it.sptep); | ||
539 | mmu_set_spte(vcpu, it.sptep, access, gw->pte_access, | 542 | mmu_set_spte(vcpu, it.sptep, access, gw->pte_access, |
540 | user_fault, write_fault, emulate, it.level, | 543 | user_fault, write_fault, emulate, it.level, |
541 | gw->gfn, pfn, prefault, map_writable); | 544 | gw->gfn, pfn, prefault, map_writable); |
@@ -599,11 +602,9 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code, | |||
599 | */ | 602 | */ |
600 | if (!r) { | 603 | if (!r) { |
601 | pgprintk("%s: guest page fault\n", __func__); | 604 | pgprintk("%s: guest page fault\n", __func__); |
602 | if (!prefault) { | 605 | if (!prefault) |
603 | inject_page_fault(vcpu, &walker.fault); | 606 | inject_page_fault(vcpu, &walker.fault); |
604 | /* reset fork detector */ | 607 | |
605 | vcpu->arch.last_pt_write_count = 0; | ||
606 | } | ||
607 | return 0; | 608 | return 0; |
608 | } | 609 | } |
609 | 610 | ||
@@ -631,7 +632,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code, | |||
631 | if (mmu_notifier_retry(vcpu, mmu_seq)) | 632 | if (mmu_notifier_retry(vcpu, mmu_seq)) |
632 | goto out_unlock; | 633 | goto out_unlock; |
633 | 634 | ||
634 | trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT); | 635 | kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT); |
635 | kvm_mmu_free_some_pages(vcpu); | 636 | kvm_mmu_free_some_pages(vcpu); |
636 | if (!force_pt_level) | 637 | if (!force_pt_level) |
637 | transparent_hugepage_adjust(vcpu, &walker.gfn, &pfn, &level); | 638 | transparent_hugepage_adjust(vcpu, &walker.gfn, &pfn, &level); |
@@ -641,11 +642,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code, | |||
641 | pgprintk("%s: shadow pte %p %llx emulate %d\n", __func__, | 642 | pgprintk("%s: shadow pte %p %llx emulate %d\n", __func__, |
642 | sptep, *sptep, emulate); | 643 | sptep, *sptep, emulate); |
643 | 644 | ||
644 | if (!emulate) | ||
645 | vcpu->arch.last_pt_write_count = 0; /* reset fork detector */ | ||
646 | |||
647 | ++vcpu->stat.pf_fixed; | 645 | ++vcpu->stat.pf_fixed; |
648 | trace_kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT); | 646 | kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT); |
649 | spin_unlock(&vcpu->kvm->mmu_lock); | 647 | spin_unlock(&vcpu->kvm->mmu_lock); |
650 | 648 | ||
651 | return emulate; | 649 | return emulate; |
@@ -656,65 +654,66 @@ out_unlock: | |||
656 | return 0; | 654 | return 0; |
657 | } | 655 | } |
658 | 656 | ||
657 | static gpa_t FNAME(get_level1_sp_gpa)(struct kvm_mmu_page *sp) | ||
658 | { | ||
659 | int offset = 0; | ||
660 | |||
661 | WARN_ON(sp->role.level != 1); | ||
662 | |||
663 | if (PTTYPE == 32) | ||
664 | offset = sp->role.quadrant << PT64_LEVEL_BITS; | ||
665 | |||
666 | return gfn_to_gpa(sp->gfn) + offset * sizeof(pt_element_t); | ||
667 | } | ||
668 | |||
659 | static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) | 669 | static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) |
660 | { | 670 | { |
661 | struct kvm_shadow_walk_iterator iterator; | 671 | struct kvm_shadow_walk_iterator iterator; |
662 | struct kvm_mmu_page *sp; | 672 | struct kvm_mmu_page *sp; |
663 | gpa_t pte_gpa = -1; | ||
664 | int level; | 673 | int level; |
665 | u64 *sptep; | 674 | u64 *sptep; |
666 | int need_flush = 0; | ||
667 | 675 | ||
668 | vcpu_clear_mmio_info(vcpu, gva); | 676 | vcpu_clear_mmio_info(vcpu, gva); |
669 | 677 | ||
670 | spin_lock(&vcpu->kvm->mmu_lock); | 678 | /* |
679 | * No need to check return value here, rmap_can_add() can | ||
680 | * help us to skip pte prefetch later. | ||
681 | */ | ||
682 | mmu_topup_memory_caches(vcpu); | ||
671 | 683 | ||
684 | spin_lock(&vcpu->kvm->mmu_lock); | ||
672 | for_each_shadow_entry(vcpu, gva, iterator) { | 685 | for_each_shadow_entry(vcpu, gva, iterator) { |
673 | level = iterator.level; | 686 | level = iterator.level; |
674 | sptep = iterator.sptep; | 687 | sptep = iterator.sptep; |
675 | 688 | ||
676 | sp = page_header(__pa(sptep)); | 689 | sp = page_header(__pa(sptep)); |
677 | if (is_last_spte(*sptep, level)) { | 690 | if (is_last_spte(*sptep, level)) { |
678 | int offset, shift; | 691 | pt_element_t gpte; |
692 | gpa_t pte_gpa; | ||
679 | 693 | ||
680 | if (!sp->unsync) | 694 | if (!sp->unsync) |
681 | break; | 695 | break; |
682 | 696 | ||
683 | shift = PAGE_SHIFT - | 697 | pte_gpa = FNAME(get_level1_sp_gpa)(sp); |
684 | (PT_LEVEL_BITS - PT64_LEVEL_BITS) * level; | ||
685 | offset = sp->role.quadrant << shift; | ||
686 | |||
687 | pte_gpa = (sp->gfn << PAGE_SHIFT) + offset; | ||
688 | pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t); | 698 | pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t); |
689 | 699 | ||
690 | if (is_shadow_present_pte(*sptep)) { | 700 | if (mmu_page_zap_pte(vcpu->kvm, sp, sptep)) |
691 | if (is_large_pte(*sptep)) | 701 | kvm_flush_remote_tlbs(vcpu->kvm); |
692 | --vcpu->kvm->stat.lpages; | ||
693 | drop_spte(vcpu->kvm, sptep); | ||
694 | need_flush = 1; | ||
695 | } else if (is_mmio_spte(*sptep)) | ||
696 | mmu_spte_clear_no_track(sptep); | ||
697 | 702 | ||
698 | break; | 703 | if (!rmap_can_add(vcpu)) |
704 | break; | ||
705 | |||
706 | if (kvm_read_guest_atomic(vcpu->kvm, pte_gpa, &gpte, | ||
707 | sizeof(pt_element_t))) | ||
708 | break; | ||
709 | |||
710 | FNAME(update_pte)(vcpu, sp, sptep, &gpte); | ||
699 | } | 711 | } |
700 | 712 | ||
701 | if (!is_shadow_present_pte(*sptep) || !sp->unsync_children) | 713 | if (!is_shadow_present_pte(*sptep) || !sp->unsync_children) |
702 | break; | 714 | break; |
703 | } | 715 | } |
704 | |||
705 | if (need_flush) | ||
706 | kvm_flush_remote_tlbs(vcpu->kvm); | ||
707 | |||
708 | atomic_inc(&vcpu->kvm->arch.invlpg_counter); | ||
709 | |||
710 | spin_unlock(&vcpu->kvm->mmu_lock); | 716 | spin_unlock(&vcpu->kvm->mmu_lock); |
711 | |||
712 | if (pte_gpa == -1) | ||
713 | return; | ||
714 | |||
715 | if (mmu_topup_memory_caches(vcpu)) | ||
716 | return; | ||
717 | kvm_mmu_pte_write(vcpu, pte_gpa, NULL, sizeof(pt_element_t), 0); | ||
718 | } | 717 | } |
719 | 718 | ||
720 | static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access, | 719 | static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr, u32 access, |
@@ -769,19 +768,14 @@ static gpa_t FNAME(gva_to_gpa_nested)(struct kvm_vcpu *vcpu, gva_t vaddr, | |||
769 | */ | 768 | */ |
770 | static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | 769 | static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) |
771 | { | 770 | { |
772 | int i, offset, nr_present; | 771 | int i, nr_present = 0; |
773 | bool host_writable; | 772 | bool host_writable; |
774 | gpa_t first_pte_gpa; | 773 | gpa_t first_pte_gpa; |
775 | 774 | ||
776 | offset = nr_present = 0; | ||
777 | |||
778 | /* direct kvm_mmu_page can not be unsync. */ | 775 | /* direct kvm_mmu_page can not be unsync. */ |
779 | BUG_ON(sp->role.direct); | 776 | BUG_ON(sp->role.direct); |
780 | 777 | ||
781 | if (PTTYPE == 32) | 778 | first_pte_gpa = FNAME(get_level1_sp_gpa)(sp); |
782 | offset = sp->role.quadrant << PT64_LEVEL_BITS; | ||
783 | |||
784 | first_pte_gpa = gfn_to_gpa(sp->gfn) + offset * sizeof(pt_element_t); | ||
785 | 779 | ||
786 | for (i = 0; i < PT64_ENT_PER_PAGE; i++) { | 780 | for (i = 0; i < PT64_ENT_PER_PAGE; i++) { |
787 | unsigned pte_access; | 781 | unsigned pte_access; |