diff options
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r-- | arch/x86/kvm/mmu.c | 86 |
1 files changed, 69 insertions, 17 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index eca41ae9f453..818b92ad82cf 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -156,6 +156,8 @@ module_param(oos_shadow, bool, 0644); | |||
156 | #define CREATE_TRACE_POINTS | 156 | #define CREATE_TRACE_POINTS |
157 | #include "mmutrace.h" | 157 | #include "mmutrace.h" |
158 | 158 | ||
159 | #define SPTE_HOST_WRITEABLE (1ULL << PT_FIRST_AVAIL_BITS_SHIFT) | ||
160 | |||
159 | #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) | 161 | #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) |
160 | 162 | ||
161 | struct kvm_rmap_desc { | 163 | struct kvm_rmap_desc { |
@@ -634,9 +636,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) | |||
634 | if (*spte & shadow_accessed_mask) | 636 | if (*spte & shadow_accessed_mask) |
635 | kvm_set_pfn_accessed(pfn); | 637 | kvm_set_pfn_accessed(pfn); |
636 | if (is_writeble_pte(*spte)) | 638 | if (is_writeble_pte(*spte)) |
637 | kvm_release_pfn_dirty(pfn); | 639 | kvm_set_pfn_dirty(pfn); |
638 | else | ||
639 | kvm_release_pfn_clean(pfn); | ||
640 | rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], sp->role.level); | 640 | rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], sp->role.level); |
641 | if (!*rmapp) { | 641 | if (!*rmapp) { |
642 | printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); | 642 | printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); |
@@ -748,7 +748,8 @@ 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, |
752 | unsigned long data) | ||
752 | { | 753 | { |
753 | u64 *spte; | 754 | u64 *spte; |
754 | int need_tlb_flush = 0; | 755 | int need_tlb_flush = 0; |
@@ -763,8 +764,47 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp) | |||
763 | return need_tlb_flush; | 764 | return need_tlb_flush; |
764 | } | 765 | } |
765 | 766 | ||
767 | static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, | ||
768 | unsigned long data) | ||
769 | { | ||
770 | int need_flush = 0; | ||
771 | u64 *spte, new_spte; | ||
772 | pte_t *ptep = (pte_t *)data; | ||
773 | pfn_t new_pfn; | ||
774 | |||
775 | WARN_ON(pte_huge(*ptep)); | ||
776 | new_pfn = pte_pfn(*ptep); | ||
777 | spte = rmap_next(kvm, rmapp, NULL); | ||
778 | while (spte) { | ||
779 | BUG_ON(!is_shadow_present_pte(*spte)); | ||
780 | rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte); | ||
781 | need_flush = 1; | ||
782 | if (pte_write(*ptep)) { | ||
783 | rmap_remove(kvm, spte); | ||
784 | __set_spte(spte, shadow_trap_nonpresent_pte); | ||
785 | spte = rmap_next(kvm, rmapp, NULL); | ||
786 | } else { | ||
787 | new_spte = *spte &~ (PT64_BASE_ADDR_MASK); | ||
788 | new_spte |= (u64)new_pfn << PAGE_SHIFT; | ||
789 | |||
790 | new_spte &= ~PT_WRITABLE_MASK; | ||
791 | new_spte &= ~SPTE_HOST_WRITEABLE; | ||
792 | if (is_writeble_pte(*spte)) | ||
793 | kvm_set_pfn_dirty(spte_to_pfn(*spte)); | ||
794 | __set_spte(spte, new_spte); | ||
795 | spte = rmap_next(kvm, rmapp, spte); | ||
796 | } | ||
797 | } | ||
798 | if (need_flush) | ||
799 | kvm_flush_remote_tlbs(kvm); | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
766 | static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | 804 | static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, |
767 | int (*handler)(struct kvm *kvm, unsigned long *rmapp)) | 805 | unsigned long data, |
806 | int (*handler)(struct kvm *kvm, unsigned long *rmapp, | ||
807 | unsigned long data)) | ||
768 | { | 808 | { |
769 | int i, j; | 809 | int i, j; |
770 | int retval = 0; | 810 | int retval = 0; |
@@ -786,13 +826,15 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | |||
786 | if (hva >= start && hva < end) { | 826 | if (hva >= start && hva < end) { |
787 | gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; | 827 | gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; |
788 | 828 | ||
789 | retval |= handler(kvm, &memslot->rmap[gfn_offset]); | 829 | retval |= handler(kvm, &memslot->rmap[gfn_offset], |
830 | data); | ||
790 | 831 | ||
791 | for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { | 832 | for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { |
792 | int idx = gfn_offset; | 833 | int idx = gfn_offset; |
793 | idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j); | 834 | idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j); |
794 | retval |= handler(kvm, | 835 | retval |= handler(kvm, |
795 | &memslot->lpage_info[j][idx].rmap_pde); | 836 | &memslot->lpage_info[j][idx].rmap_pde, |
837 | data); | ||
796 | } | 838 | } |
797 | } | 839 | } |
798 | } | 840 | } |
@@ -802,10 +844,16 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | |||
802 | 844 | ||
803 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) | 845 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) |
804 | { | 846 | { |
805 | return kvm_handle_hva(kvm, hva, kvm_unmap_rmapp); | 847 | return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp); |
806 | } | 848 | } |
807 | 849 | ||
808 | static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp) | 850 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) |
851 | { | ||
852 | kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp); | ||
853 | } | ||
854 | |||
855 | static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, | ||
856 | unsigned long data) | ||
809 | { | 857 | { |
810 | u64 *spte; | 858 | u64 *spte; |
811 | int young = 0; | 859 | int young = 0; |
@@ -841,13 +889,13 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) | |||
841 | gfn = unalias_gfn(vcpu->kvm, gfn); | 889 | gfn = unalias_gfn(vcpu->kvm, gfn); |
842 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); | 890 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); |
843 | 891 | ||
844 | kvm_unmap_rmapp(vcpu->kvm, rmapp); | 892 | kvm_unmap_rmapp(vcpu->kvm, rmapp, 0); |
845 | kvm_flush_remote_tlbs(vcpu->kvm); | 893 | kvm_flush_remote_tlbs(vcpu->kvm); |
846 | } | 894 | } |
847 | 895 | ||
848 | int kvm_age_hva(struct kvm *kvm, unsigned long hva) | 896 | int kvm_age_hva(struct kvm *kvm, unsigned long hva) |
849 | { | 897 | { |
850 | return kvm_handle_hva(kvm, hva, kvm_age_rmapp); | 898 | return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp); |
851 | } | 899 | } |
852 | 900 | ||
853 | #ifdef MMU_DEBUG | 901 | #ifdef MMU_DEBUG |
@@ -1756,7 +1804,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1756 | unsigned pte_access, int user_fault, | 1804 | unsigned pte_access, int user_fault, |
1757 | int write_fault, int dirty, int level, | 1805 | int write_fault, int dirty, int level, |
1758 | gfn_t gfn, pfn_t pfn, bool speculative, | 1806 | gfn_t gfn, pfn_t pfn, bool speculative, |
1759 | bool can_unsync) | 1807 | bool can_unsync, bool reset_host_protection) |
1760 | { | 1808 | { |
1761 | u64 spte; | 1809 | u64 spte; |
1762 | int ret = 0; | 1810 | int ret = 0; |
@@ -1783,6 +1831,9 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1783 | spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, | 1831 | spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, |
1784 | kvm_is_mmio_pfn(pfn)); | 1832 | kvm_is_mmio_pfn(pfn)); |
1785 | 1833 | ||
1834 | if (reset_host_protection) | ||
1835 | spte |= SPTE_HOST_WRITEABLE; | ||
1836 | |||
1786 | spte |= (u64)pfn << PAGE_SHIFT; | 1837 | spte |= (u64)pfn << PAGE_SHIFT; |
1787 | 1838 | ||
1788 | if ((pte_access & ACC_WRITE_MASK) | 1839 | if ((pte_access & ACC_WRITE_MASK) |
@@ -1828,7 +1879,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1828 | unsigned pt_access, unsigned pte_access, | 1879 | unsigned pt_access, unsigned pte_access, |
1829 | int user_fault, int write_fault, int dirty, | 1880 | int user_fault, int write_fault, int dirty, |
1830 | int *ptwrite, int level, gfn_t gfn, | 1881 | int *ptwrite, int level, gfn_t gfn, |
1831 | pfn_t pfn, bool speculative) | 1882 | pfn_t pfn, bool speculative, |
1883 | bool reset_host_protection) | ||
1832 | { | 1884 | { |
1833 | int was_rmapped = 0; | 1885 | int was_rmapped = 0; |
1834 | int was_writeble = is_writeble_pte(*sptep); | 1886 | int was_writeble = is_writeble_pte(*sptep); |
@@ -1860,7 +1912,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1860 | } | 1912 | } |
1861 | 1913 | ||
1862 | if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault, | 1914 | if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault, |
1863 | dirty, level, gfn, pfn, speculative, true)) { | 1915 | dirty, level, gfn, pfn, speculative, true, |
1916 | reset_host_protection)) { | ||
1864 | if (write_fault) | 1917 | if (write_fault) |
1865 | *ptwrite = 1; | 1918 | *ptwrite = 1; |
1866 | kvm_x86_ops->tlb_flush(vcpu); | 1919 | kvm_x86_ops->tlb_flush(vcpu); |
@@ -1877,8 +1930,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1877 | page_header_update_slot(vcpu->kvm, sptep, gfn); | 1930 | page_header_update_slot(vcpu->kvm, sptep, gfn); |
1878 | if (!was_rmapped) { | 1931 | if (!was_rmapped) { |
1879 | rmap_count = rmap_add(vcpu, sptep, gfn); | 1932 | rmap_count = rmap_add(vcpu, sptep, gfn); |
1880 | if (!is_rmap_spte(*sptep)) | 1933 | kvm_release_pfn_clean(pfn); |
1881 | kvm_release_pfn_clean(pfn); | ||
1882 | if (rmap_count > RMAP_RECYCLE_THRESHOLD) | 1934 | if (rmap_count > RMAP_RECYCLE_THRESHOLD) |
1883 | rmap_recycle(vcpu, sptep, gfn); | 1935 | rmap_recycle(vcpu, sptep, gfn); |
1884 | } else { | 1936 | } else { |
@@ -1909,7 +1961,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, | |||
1909 | if (iterator.level == level) { | 1961 | if (iterator.level == level) { |
1910 | mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, | 1962 | mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, |
1911 | 0, write, 1, &pt_write, | 1963 | 0, write, 1, &pt_write, |
1912 | level, gfn, pfn, false); | 1964 | level, gfn, pfn, false, true); |
1913 | ++vcpu->stat.pf_fixed; | 1965 | ++vcpu->stat.pf_fixed; |
1914 | break; | 1966 | break; |
1915 | } | 1967 | } |