diff options
-rw-r--r-- | arch/x86/kvm/mmu.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index c07b9a200bc8..ff95d418750d 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -307,24 +307,42 @@ static bool spte_has_volatile_bits(u64 spte) | |||
307 | if (!is_shadow_present_pte(spte)) | 307 | if (!is_shadow_present_pte(spte)) |
308 | return false; | 308 | return false; |
309 | 309 | ||
310 | if (spte & shadow_accessed_mask) | 310 | if ((spte & shadow_accessed_mask) && |
311 | (!is_writable_pte(spte) || (spte & shadow_dirty_mask))) | ||
311 | return false; | 312 | return false; |
312 | 313 | ||
313 | return true; | 314 | return true; |
314 | } | 315 | } |
315 | 316 | ||
317 | static bool spte_is_bit_cleared(u64 old_spte, u64 new_spte, u64 bit_mask) | ||
318 | { | ||
319 | return (old_spte & bit_mask) && !(new_spte & bit_mask); | ||
320 | } | ||
321 | |||
316 | static void update_spte(u64 *sptep, u64 new_spte) | 322 | static void update_spte(u64 *sptep, u64 new_spte) |
317 | { | 323 | { |
318 | u64 old_spte; | 324 | u64 mask, old_spte = *sptep; |
325 | |||
326 | WARN_ON(!is_rmap_spte(new_spte)); | ||
319 | 327 | ||
320 | if (!shadow_accessed_mask || (new_spte & shadow_accessed_mask) || | 328 | new_spte |= old_spte & shadow_dirty_mask; |
321 | !is_rmap_spte(*sptep)) | 329 | |
330 | mask = shadow_accessed_mask; | ||
331 | if (is_writable_pte(old_spte)) | ||
332 | mask |= shadow_dirty_mask; | ||
333 | |||
334 | if (!spte_has_volatile_bits(old_spte) || (new_spte & mask) == mask) | ||
322 | __set_spte(sptep, new_spte); | 335 | __set_spte(sptep, new_spte); |
323 | else { | 336 | else |
324 | old_spte = __xchg_spte(sptep, new_spte); | 337 | old_spte = __xchg_spte(sptep, new_spte); |
325 | if (old_spte & shadow_accessed_mask) | 338 | |
326 | kvm_set_pfn_accessed(spte_to_pfn(old_spte)); | 339 | if (!shadow_accessed_mask) |
327 | } | 340 | return; |
341 | |||
342 | if (spte_is_bit_cleared(old_spte, new_spte, shadow_accessed_mask)) | ||
343 | kvm_set_pfn_accessed(spte_to_pfn(old_spte)); | ||
344 | if (spte_is_bit_cleared(old_spte, new_spte, shadow_dirty_mask)) | ||
345 | kvm_set_pfn_dirty(spte_to_pfn(old_spte)); | ||
328 | } | 346 | } |
329 | 347 | ||
330 | static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, | 348 | static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, |
@@ -704,7 +722,7 @@ static void set_spte_track_bits(u64 *sptep, u64 new_spte) | |||
704 | pfn = spte_to_pfn(old_spte); | 722 | pfn = spte_to_pfn(old_spte); |
705 | if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) | 723 | if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) |
706 | kvm_set_pfn_accessed(pfn); | 724 | kvm_set_pfn_accessed(pfn); |
707 | if (is_writable_pte(old_spte)) | 725 | if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask)) |
708 | kvm_set_pfn_dirty(pfn); | 726 | kvm_set_pfn_dirty(pfn); |
709 | } | 727 | } |
710 | 728 | ||
@@ -759,13 +777,6 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn) | |||
759 | } | 777 | } |
760 | spte = rmap_next(kvm, rmapp, spte); | 778 | spte = rmap_next(kvm, rmapp, spte); |
761 | } | 779 | } |
762 | if (write_protected) { | ||
763 | pfn_t pfn; | ||
764 | |||
765 | spte = rmap_next(kvm, rmapp, NULL); | ||
766 | pfn = spte_to_pfn(*spte); | ||
767 | kvm_set_pfn_dirty(pfn); | ||
768 | } | ||
769 | 780 | ||
770 | /* check for huge page mappings */ | 781 | /* check for huge page mappings */ |
771 | for (i = PT_DIRECTORY_LEVEL; | 782 | for (i = PT_DIRECTORY_LEVEL; |
@@ -1938,7 +1949,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1938 | * whether the guest actually used the pte (in order to detect | 1949 | * whether the guest actually used the pte (in order to detect |
1939 | * demand paging). | 1950 | * demand paging). |
1940 | */ | 1951 | */ |
1941 | spte = shadow_base_present_pte | shadow_dirty_mask; | 1952 | spte = shadow_base_present_pte; |
1942 | if (!speculative) | 1953 | if (!speculative) |
1943 | spte |= shadow_accessed_mask; | 1954 | spte |= shadow_accessed_mask; |
1944 | if (!dirty) | 1955 | if (!dirty) |
@@ -1999,8 +2010,6 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
1999 | mark_page_dirty(vcpu->kvm, gfn); | 2010 | mark_page_dirty(vcpu->kvm, gfn); |
2000 | 2011 | ||
2001 | set_pte: | 2012 | set_pte: |
2002 | if (is_writable_pte(*sptep) && !is_writable_pte(spte)) | ||
2003 | kvm_set_pfn_dirty(pfn); | ||
2004 | update_spte(sptep, spte); | 2013 | update_spte(sptep, spte); |
2005 | done: | 2014 | done: |
2006 | return ret; | 2015 | return ret; |