diff options
-rw-r--r-- | arch/x86/kvm/mmu.c | 15 | ||||
-rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 18 |
2 files changed, 26 insertions, 7 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 6c67b230e958..5cd8b4ec3a01 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 { |
@@ -1754,7 +1756,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1754 | unsigned pte_access, int user_fault, | 1756 | unsigned pte_access, int user_fault, |
1755 | int write_fault, int dirty, int level, | 1757 | int write_fault, int dirty, int level, |
1756 | gfn_t gfn, pfn_t pfn, bool speculative, | 1758 | gfn_t gfn, pfn_t pfn, bool speculative, |
1757 | bool can_unsync) | 1759 | bool can_unsync, bool reset_host_protection) |
1758 | { | 1760 | { |
1759 | u64 spte; | 1761 | u64 spte; |
1760 | int ret = 0; | 1762 | int ret = 0; |
@@ -1781,6 +1783,9 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1781 | spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, | 1783 | spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, |
1782 | kvm_is_mmio_pfn(pfn)); | 1784 | kvm_is_mmio_pfn(pfn)); |
1783 | 1785 | ||
1786 | if (reset_host_protection) | ||
1787 | spte |= SPTE_HOST_WRITEABLE; | ||
1788 | |||
1784 | spte |= (u64)pfn << PAGE_SHIFT; | 1789 | spte |= (u64)pfn << PAGE_SHIFT; |
1785 | 1790 | ||
1786 | if ((pte_access & ACC_WRITE_MASK) | 1791 | if ((pte_access & ACC_WRITE_MASK) |
@@ -1826,7 +1831,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1826 | unsigned pt_access, unsigned pte_access, | 1831 | unsigned pt_access, unsigned pte_access, |
1827 | int user_fault, int write_fault, int dirty, | 1832 | int user_fault, int write_fault, int dirty, |
1828 | int *ptwrite, int level, gfn_t gfn, | 1833 | int *ptwrite, int level, gfn_t gfn, |
1829 | pfn_t pfn, bool speculative) | 1834 | pfn_t pfn, bool speculative, |
1835 | bool reset_host_protection) | ||
1830 | { | 1836 | { |
1831 | int was_rmapped = 0; | 1837 | int was_rmapped = 0; |
1832 | int was_writeble = is_writeble_pte(*sptep); | 1838 | int was_writeble = is_writeble_pte(*sptep); |
@@ -1858,7 +1864,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1858 | } | 1864 | } |
1859 | 1865 | ||
1860 | if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault, | 1866 | if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault, |
1861 | dirty, level, gfn, pfn, speculative, true)) { | 1867 | dirty, level, gfn, pfn, speculative, true, |
1868 | reset_host_protection)) { | ||
1862 | if (write_fault) | 1869 | if (write_fault) |
1863 | *ptwrite = 1; | 1870 | *ptwrite = 1; |
1864 | kvm_x86_ops->tlb_flush(vcpu); | 1871 | kvm_x86_ops->tlb_flush(vcpu); |
@@ -1906,7 +1913,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, | |||
1906 | if (iterator.level == level) { | 1913 | if (iterator.level == level) { |
1907 | mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, | 1914 | mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, |
1908 | 0, write, 1, &pt_write, | 1915 | 0, write, 1, &pt_write, |
1909 | level, gfn, pfn, false); | 1916 | level, gfn, pfn, false, true); |
1910 | ++vcpu->stat.pf_fixed; | 1917 | ++vcpu->stat.pf_fixed; |
1911 | break; | 1918 | break; |
1912 | } | 1919 | } |
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index d2fec9c12d22..72558f8ff3f5 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
@@ -273,9 +273,13 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, | |||
273 | if (mmu_notifier_retry(vcpu, vcpu->arch.update_pte.mmu_seq)) | 273 | if (mmu_notifier_retry(vcpu, vcpu->arch.update_pte.mmu_seq)) |
274 | return; | 274 | return; |
275 | kvm_get_pfn(pfn); | 275 | kvm_get_pfn(pfn); |
276 | /* | ||
277 | * we call mmu_set_spte() with reset_host_protection = true beacuse that | ||
278 | * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1). | ||
279 | */ | ||
276 | mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, | 280 | mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, |
277 | gpte & PT_DIRTY_MASK, NULL, PT_PAGE_TABLE_LEVEL, | 281 | gpte & PT_DIRTY_MASK, NULL, PT_PAGE_TABLE_LEVEL, |
278 | gpte_to_gfn(gpte), pfn, true); | 282 | gpte_to_gfn(gpte), pfn, true, true); |
279 | } | 283 | } |
280 | 284 | ||
281 | /* | 285 | /* |
@@ -308,7 +312,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
308 | user_fault, write_fault, | 312 | user_fault, write_fault, |
309 | gw->ptes[gw->level-1] & PT_DIRTY_MASK, | 313 | gw->ptes[gw->level-1] & PT_DIRTY_MASK, |
310 | ptwrite, level, | 314 | ptwrite, level, |
311 | gw->gfn, pfn, false); | 315 | gw->gfn, pfn, false, true); |
312 | break; | 316 | break; |
313 | } | 317 | } |
314 | 318 | ||
@@ -558,6 +562,7 @@ static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu, | |||
558 | static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | 562 | static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) |
559 | { | 563 | { |
560 | int i, offset, nr_present; | 564 | int i, offset, nr_present; |
565 | bool reset_host_protection; | ||
561 | 566 | ||
562 | offset = nr_present = 0; | 567 | offset = nr_present = 0; |
563 | 568 | ||
@@ -595,9 +600,16 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | |||
595 | 600 | ||
596 | nr_present++; | 601 | nr_present++; |
597 | pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); | 602 | pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); |
603 | if (!(sp->spt[i] & SPTE_HOST_WRITEABLE)) { | ||
604 | pte_access &= ~ACC_WRITE_MASK; | ||
605 | reset_host_protection = 0; | ||
606 | } else { | ||
607 | reset_host_protection = 1; | ||
608 | } | ||
598 | set_spte(vcpu, &sp->spt[i], pte_access, 0, 0, | 609 | set_spte(vcpu, &sp->spt[i], pte_access, 0, 0, |
599 | is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn, | 610 | is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn, |
600 | spte_to_pfn(sp->spt[i]), true, false); | 611 | spte_to_pfn(sp->spt[i]), true, false, |
612 | reset_host_protection); | ||
601 | } | 613 | } |
602 | 614 | ||
603 | return !nr_present; | 615 | return !nr_present; |