aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/paging_tmpl.h
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/kvm/paging_tmpl.h
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/kvm/paging_tmpl.h')
-rw-r--r--arch/x86/kvm/paging_tmpl.h46
1 files changed, 19 insertions, 27 deletions
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 }