aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorXiao Guangrong <xiaoguangrong@cn.fujitsu.com>2011-07-11 15:24:39 -0400
committerAvi Kivity <avi@redhat.com>2011-07-24 04:50:27 -0400
commit640d9b0dbe9f744ac8fd517a8f6afe238f8f525b (patch)
treeff4543527ee35018f26d686e5c46a4c100dda0ef /arch/x86
parentbebb106a5afa32efdf5332ed4a40bf4d6d06b56e (diff)
KVM: MMU: optimize to handle dirty bit
If dirty bit is not set, we can make the pte access read-only to avoid handing dirty bit everywhere Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kvm/mmu.c13
-rw-r--r--arch/x86/kvm/paging_tmpl.h46
2 files changed, 25 insertions, 34 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index d1986b7dcec7..98812c25727b 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1923,7 +1923,7 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
1923 1923
1924static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, 1924static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
1925 unsigned pte_access, int user_fault, 1925 unsigned pte_access, int user_fault,
1926 int write_fault, int dirty, int level, 1926 int write_fault, int level,
1927 gfn_t gfn, pfn_t pfn, bool speculative, 1927 gfn_t gfn, pfn_t pfn, bool speculative,
1928 bool can_unsync, bool host_writable) 1928 bool can_unsync, bool host_writable)
1929{ 1929{
@@ -1938,8 +1938,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
1938 spte = PT_PRESENT_MASK; 1938 spte = PT_PRESENT_MASK;
1939 if (!speculative) 1939 if (!speculative)
1940 spte |= shadow_accessed_mask; 1940 spte |= shadow_accessed_mask;
1941 if (!dirty) 1941
1942 pte_access &= ~ACC_WRITE_MASK;
1943 if (pte_access & ACC_EXEC_MASK) 1942 if (pte_access & ACC_EXEC_MASK)
1944 spte |= shadow_x_mask; 1943 spte |= shadow_x_mask;
1945 else 1944 else
@@ -2023,7 +2022,7 @@ done:
2023 2022
2024static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, 2023static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
2025 unsigned pt_access, unsigned pte_access, 2024 unsigned pt_access, unsigned pte_access,
2026 int user_fault, int write_fault, int dirty, 2025 int user_fault, int write_fault,
2027 int *ptwrite, int level, gfn_t gfn, 2026 int *ptwrite, int level, gfn_t gfn,
2028 pfn_t pfn, bool speculative, 2027 pfn_t pfn, bool speculative,
2029 bool host_writable) 2028 bool host_writable)
@@ -2059,7 +2058,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
2059 } 2058 }
2060 2059
2061 if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault, 2060 if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault,
2062 dirty, level, gfn, pfn, speculative, true, 2061 level, gfn, pfn, speculative, true,
2063 host_writable)) { 2062 host_writable)) {
2064 if (write_fault) 2063 if (write_fault)
2065 *ptwrite = 1; 2064 *ptwrite = 1;
@@ -2129,7 +2128,7 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
2129 2128
2130 for (i = 0; i < ret; i++, gfn++, start++) 2129 for (i = 0; i < ret; i++, gfn++, start++)
2131 mmu_set_spte(vcpu, start, ACC_ALL, 2130 mmu_set_spte(vcpu, start, ACC_ALL,
2132 access, 0, 0, 1, NULL, 2131 access, 0, 0, NULL,
2133 sp->role.level, gfn, 2132 sp->role.level, gfn,
2134 page_to_pfn(pages[i]), true, true); 2133 page_to_pfn(pages[i]), true, true);
2135 2134
@@ -2193,7 +2192,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
2193 unsigned pte_access = ACC_ALL; 2192 unsigned pte_access = ACC_ALL;
2194 2193
2195 mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, pte_access, 2194 mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, pte_access,
2196 0, write, 1, &pt_write, 2195 0, write, &pt_write,
2197 level, gfn, pfn, prefault, map_writable); 2196 level, gfn, pfn, prefault, map_writable);
2198 direct_pte_prefetch(vcpu, iterator.sptep); 2197 direct_pte_prefetch(vcpu, iterator.sptep);
2199 ++vcpu->stat.pf_fixed; 2198 ++vcpu->stat.pf_fixed;
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index f0fb1a4c522d..c9fe97bd8c82 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -101,11 +101,15 @@ static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
101 return (ret != orig_pte); 101 return (ret != orig_pte);
102} 102}
103 103
104static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte) 104static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte,
105 bool last)
105{ 106{
106 unsigned access; 107 unsigned access;
107 108
108 access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK; 109 access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK;
110 if (last && !is_dirty_gpte(gpte))
111 access &= ~ACC_WRITE_MASK;
112
109#if PTTYPE == 64 113#if PTTYPE == 64
110 if (vcpu->arch.mmu.nx) 114 if (vcpu->arch.mmu.nx)
111 access &= ~(gpte >> PT64_NX_SHIFT); 115 access &= ~(gpte >> PT64_NX_SHIFT);
@@ -232,8 +236,6 @@ retry_walk:
232 pte |= PT_ACCESSED_MASK; 236 pte |= PT_ACCESSED_MASK;
233 } 237 }
234 238
235 pte_access = pt_access & FNAME(gpte_access)(vcpu, pte);
236
237 walker->ptes[walker->level - 1] = pte; 239 walker->ptes[walker->level - 1] = pte;
238 240
239 if (FNAME(is_last_gpte)(walker, vcpu, mmu, pte)) { 241 if (FNAME(is_last_gpte)(walker, vcpu, mmu, pte)) {
@@ -268,7 +270,7 @@ retry_walk:
268 break; 270 break;
269 } 271 }
270 272
271 pt_access = pte_access; 273 pt_access &= FNAME(gpte_access)(vcpu, pte, false);
272 --walker->level; 274 --walker->level;
273 } 275 }
274 276
@@ -293,6 +295,7 @@ retry_walk:
293 walker->ptes[walker->level - 1] = pte; 295 walker->ptes[walker->level - 1] = pte;
294 } 296 }
295 297
298 pte_access = pt_access & FNAME(gpte_access)(vcpu, pte, true);
296 walker->pt_access = pt_access; 299 walker->pt_access = pt_access;
297 walker->pte_access = pte_access; 300 walker->pte_access = pte_access;
298 pgprintk("%s: pte %llx pte_access %x pt_access %x\n", 301 pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
@@ -367,7 +370,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
367 return; 370 return;
368 371
369 pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte); 372 pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
370 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); 373 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, true);
371 pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte)); 374 pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte));
372 if (is_error_pfn(pfn)) { 375 if (is_error_pfn(pfn)) {
373 kvm_release_pfn_clean(pfn); 376 kvm_release_pfn_clean(pfn);
@@ -379,7 +382,7 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
379 * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1). 382 * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1).
380 */ 383 */
381 mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0, 384 mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
382 is_dirty_gpte(gpte), NULL, PT_PAGE_TABLE_LEVEL, 385 NULL, PT_PAGE_TABLE_LEVEL,
383 gpte_to_gfn(gpte), pfn, true, true); 386 gpte_to_gfn(gpte), pfn, true, true);
384} 387}
385 388
@@ -430,7 +433,6 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
430 unsigned pte_access; 433 unsigned pte_access;
431 gfn_t gfn; 434 gfn_t gfn;
432 pfn_t pfn; 435 pfn_t pfn;
433 bool dirty;
434 436
435 if (spte == sptep) 437 if (spte == sptep)
436 continue; 438 continue;
@@ -443,18 +445,18 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
443 if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte)) 445 if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte))
444 continue; 446 continue;
445 447
446 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); 448 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte,
449 true);
447 gfn = gpte_to_gfn(gpte); 450 gfn = gpte_to_gfn(gpte);
448 dirty = is_dirty_gpte(gpte);
449 pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn, 451 pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn,
450 (pte_access & ACC_WRITE_MASK) && dirty); 452 pte_access & ACC_WRITE_MASK);
451 if (is_error_pfn(pfn)) { 453 if (is_error_pfn(pfn)) {
452 kvm_release_pfn_clean(pfn); 454 kvm_release_pfn_clean(pfn);
453 break; 455 break;
454 } 456 }
455 457
456 mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0, 458 mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
457 dirty, NULL, PT_PAGE_TABLE_LEVEL, gfn, 459 NULL, PT_PAGE_TABLE_LEVEL, gfn,
458 pfn, true, true); 460 pfn, true, true);
459 } 461 }
460} 462}
@@ -470,7 +472,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
470{ 472{
471 unsigned access = gw->pt_access; 473 unsigned access = gw->pt_access;
472 struct kvm_mmu_page *sp = NULL; 474 struct kvm_mmu_page *sp = NULL;
473 bool dirty = is_dirty_gpte(gw->ptes[gw->level - 1]);
474 int top_level; 475 int top_level;
475 unsigned direct_access; 476 unsigned direct_access;
476 struct kvm_shadow_walk_iterator it; 477 struct kvm_shadow_walk_iterator it;
@@ -479,8 +480,6 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
479 return NULL; 480 return NULL;
480 481
481 direct_access = gw->pt_access & gw->pte_access; 482 direct_access = gw->pt_access & gw->pte_access;
482 if (!dirty)
483 direct_access &= ~ACC_WRITE_MASK;
484 483
485 top_level = vcpu->arch.mmu.root_level; 484 top_level = vcpu->arch.mmu.root_level;
486 if (top_level == PT32E_ROOT_LEVEL) 485 if (top_level == PT32E_ROOT_LEVEL)
@@ -539,7 +538,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
539 } 538 }
540 539
541 mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access, 540 mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access,
542 user_fault, write_fault, dirty, ptwrite, it.level, 541 user_fault, write_fault, ptwrite, it.level,
543 gw->gfn, pfn, prefault, map_writable); 542 gw->gfn, pfn, prefault, map_writable);
544 FNAME(pte_prefetch)(vcpu, gw, it.sptep); 543 FNAME(pte_prefetch)(vcpu, gw, it.sptep);
545 544
@@ -622,17 +621,9 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
622 return 0; 621 return 0;
623 622
624 /* mmio */ 623 /* mmio */
625 if (is_error_pfn(pfn)) { 624 if (is_error_pfn(pfn))
626 unsigned access = walker.pte_access;
627 bool dirty = is_dirty_gpte(walker.ptes[walker.level - 1]);
628
629 if (!dirty)
630 access &= ~ACC_WRITE_MASK;
631
632 return kvm_handle_bad_page(vcpu, mmu_is_nested(vcpu) ? 0 : 625 return kvm_handle_bad_page(vcpu, mmu_is_nested(vcpu) ? 0 :
633 addr, access, walker.gfn, pfn); 626 addr, walker.pte_access, walker.gfn, pfn);
634 }
635
636 spin_lock(&vcpu->kvm->mmu_lock); 627 spin_lock(&vcpu->kvm->mmu_lock);
637 if (mmu_notifier_retry(vcpu, mmu_seq)) 628 if (mmu_notifier_retry(vcpu, mmu_seq))
638 goto out_unlock; 629 goto out_unlock;
@@ -849,11 +840,12 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
849 } 840 }
850 841
851 nr_present++; 842 nr_present++;
852 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); 843 pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte,
844 true);
853 host_writable = sp->spt[i] & SPTE_HOST_WRITEABLE; 845 host_writable = sp->spt[i] & SPTE_HOST_WRITEABLE;
854 846
855 set_spte(vcpu, &sp->spt[i], pte_access, 0, 0, 847 set_spte(vcpu, &sp->spt[i], pte_access, 0, 0,
856 is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn, 848 PT_PAGE_TABLE_LEVEL, gfn,
857 spte_to_pfn(sp->spt[i]), true, false, 849 spte_to_pfn(sp->spt[i]), true, false,
858 host_writable); 850 host_writable);
859 } 851 }