diff options
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
| -rw-r--r-- | arch/x86/kvm/mmu.c | 62 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 14 |
3 files changed, 68 insertions, 9 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3be000435fad..d83892226f73 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -796,6 +796,7 @@ asmlinkage void kvm_handle_fault_on_reboot(void); | |||
| 796 | #define KVM_ARCH_WANT_MMU_NOTIFIER | 796 | #define KVM_ARCH_WANT_MMU_NOTIFIER |
| 797 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); | 797 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); |
| 798 | int kvm_age_hva(struct kvm *kvm, unsigned long hva); | 798 | int kvm_age_hva(struct kvm *kvm, unsigned long hva); |
| 799 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); | ||
| 799 | int cpuid_maxphyaddr(struct kvm_vcpu *vcpu); | 800 | int cpuid_maxphyaddr(struct kvm_vcpu *vcpu); |
| 800 | int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); | 801 | int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); |
| 801 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); | 802 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 5cd8b4ec3a01..685a4ffac8e6 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
| @@ -748,7 +748,7 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn) | |||
| 748 | return write_protected; | 748 | return write_protected; |
| 749 | } | 749 | } |
| 750 | 750 | ||
| 751 | static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp) | 751 | static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data) |
| 752 | { | 752 | { |
| 753 | u64 *spte; | 753 | u64 *spte; |
| 754 | int need_tlb_flush = 0; | 754 | int need_tlb_flush = 0; |
| @@ -763,8 +763,45 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp) | |||
| 763 | return need_tlb_flush; | 763 | return need_tlb_flush; |
| 764 | } | 764 | } |
| 765 | 765 | ||
| 766 | static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | 766 | static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data) |
| 767 | int (*handler)(struct kvm *kvm, unsigned long *rmapp)) | 767 | { |
| 768 | int need_flush = 0; | ||
| 769 | u64 *spte, new_spte; | ||
| 770 | pte_t *ptep = (pte_t *)data; | ||
| 771 | pfn_t new_pfn; | ||
| 772 | |||
| 773 | WARN_ON(pte_huge(*ptep)); | ||
| 774 | new_pfn = pte_pfn(*ptep); | ||
| 775 | spte = rmap_next(kvm, rmapp, NULL); | ||
| 776 | while (spte) { | ||
| 777 | BUG_ON(!is_shadow_present_pte(*spte)); | ||
| 778 | rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte); | ||
| 779 | need_flush = 1; | ||
| 780 | if (pte_write(*ptep)) { | ||
| 781 | rmap_remove(kvm, spte); | ||
| 782 | __set_spte(spte, shadow_trap_nonpresent_pte); | ||
| 783 | spte = rmap_next(kvm, rmapp, NULL); | ||
| 784 | } else { | ||
| 785 | new_spte = *spte &~ (PT64_BASE_ADDR_MASK); | ||
| 786 | new_spte |= (u64)new_pfn << PAGE_SHIFT; | ||
| 787 | |||
| 788 | new_spte &= ~PT_WRITABLE_MASK; | ||
| 789 | new_spte &= ~SPTE_HOST_WRITEABLE; | ||
| 790 | if (is_writeble_pte(*spte)) | ||
| 791 | kvm_set_pfn_dirty(spte_to_pfn(*spte)); | ||
| 792 | __set_spte(spte, new_spte); | ||
| 793 | spte = rmap_next(kvm, rmapp, spte); | ||
| 794 | } | ||
| 795 | } | ||
| 796 | if (need_flush) | ||
| 797 | kvm_flush_remote_tlbs(kvm); | ||
| 798 | |||
| 799 | return 0; | ||
| 800 | } | ||
| 801 | |||
| 802 | static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, u64 data, | ||
| 803 | int (*handler)(struct kvm *kvm, unsigned long *rmapp, | ||
| 804 | u64 data)) | ||
| 768 | { | 805 | { |
| 769 | int i, j; | 806 | int i, j; |
| 770 | int retval = 0; | 807 | int retval = 0; |
| @@ -786,13 +823,15 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | |||
| 786 | if (hva >= start && hva < end) { | 823 | if (hva >= start && hva < end) { |
| 787 | gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; | 824 | gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; |
| 788 | 825 | ||
| 789 | retval |= handler(kvm, &memslot->rmap[gfn_offset]); | 826 | retval |= handler(kvm, &memslot->rmap[gfn_offset], |
| 827 | data); | ||
| 790 | 828 | ||
| 791 | for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { | 829 | for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { |
| 792 | int idx = gfn_offset; | 830 | int idx = gfn_offset; |
| 793 | idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j); | 831 | idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j); |
| 794 | retval |= handler(kvm, | 832 | retval |= handler(kvm, |
| 795 | &memslot->lpage_info[j][idx].rmap_pde); | 833 | &memslot->lpage_info[j][idx].rmap_pde, |
| 834 | data); | ||
| 796 | } | 835 | } |
| 797 | } | 836 | } |
| 798 | } | 837 | } |
| @@ -802,10 +841,15 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | |||
| 802 | 841 | ||
| 803 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) | 842 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) |
| 804 | { | 843 | { |
| 805 | return kvm_handle_hva(kvm, hva, kvm_unmap_rmapp); | 844 | return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp); |
| 845 | } | ||
| 846 | |||
| 847 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) | ||
| 848 | { | ||
| 849 | kvm_handle_hva(kvm, hva, (u64)&pte, kvm_set_pte_rmapp); | ||
| 806 | } | 850 | } |
| 807 | 851 | ||
| 808 | static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp) | 852 | static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data) |
| 809 | { | 853 | { |
| 810 | u64 *spte; | 854 | u64 *spte; |
| 811 | int young = 0; | 855 | int young = 0; |
| @@ -841,13 +885,13 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) | |||
| 841 | gfn = unalias_gfn(vcpu->kvm, gfn); | 885 | gfn = unalias_gfn(vcpu->kvm, gfn); |
| 842 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); | 886 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); |
| 843 | 887 | ||
| 844 | kvm_unmap_rmapp(vcpu->kvm, rmapp); | 888 | kvm_unmap_rmapp(vcpu->kvm, rmapp, 0); |
| 845 | kvm_flush_remote_tlbs(vcpu->kvm); | 889 | kvm_flush_remote_tlbs(vcpu->kvm); |
| 846 | } | 890 | } |
| 847 | 891 | ||
| 848 | int kvm_age_hva(struct kvm *kvm, unsigned long hva) | 892 | int kvm_age_hva(struct kvm *kvm, unsigned long hva) |
| 849 | { | 893 | { |
| 850 | return kvm_handle_hva(kvm, hva, kvm_age_rmapp); | 894 | return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp); |
| 851 | } | 895 | } |
| 852 | 896 | ||
| 853 | #ifdef MMU_DEBUG | 897 | #ifdef MMU_DEBUG |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e79c54034bcd..b7c78a403dc2 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
| @@ -850,6 +850,19 @@ static void kvm_mmu_notifier_invalidate_page(struct mmu_notifier *mn, | |||
| 850 | 850 | ||
| 851 | } | 851 | } |
| 852 | 852 | ||
| 853 | static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn, | ||
| 854 | struct mm_struct *mm, | ||
| 855 | unsigned long address, | ||
| 856 | pte_t pte) | ||
| 857 | { | ||
| 858 | struct kvm *kvm = mmu_notifier_to_kvm(mn); | ||
| 859 | |||
| 860 | spin_lock(&kvm->mmu_lock); | ||
| 861 | kvm->mmu_notifier_seq++; | ||
| 862 | kvm_set_spte_hva(kvm, address, pte); | ||
| 863 | spin_unlock(&kvm->mmu_lock); | ||
| 864 | } | ||
| 865 | |||
| 853 | static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, | 866 | static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, |
| 854 | struct mm_struct *mm, | 867 | struct mm_struct *mm, |
| 855 | unsigned long start, | 868 | unsigned long start, |
| @@ -929,6 +942,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = { | |||
| 929 | .invalidate_range_start = kvm_mmu_notifier_invalidate_range_start, | 942 | .invalidate_range_start = kvm_mmu_notifier_invalidate_range_start, |
| 930 | .invalidate_range_end = kvm_mmu_notifier_invalidate_range_end, | 943 | .invalidate_range_end = kvm_mmu_notifier_invalidate_range_end, |
| 931 | .clear_flush_young = kvm_mmu_notifier_clear_flush_young, | 944 | .clear_flush_young = kvm_mmu_notifier_clear_flush_young, |
| 945 | .change_pte = kvm_mmu_notifier_change_pte, | ||
| 932 | .release = kvm_mmu_notifier_release, | 946 | .release = kvm_mmu_notifier_release, |
| 933 | }; | 947 | }; |
| 934 | #endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */ | 948 | #endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */ |
