diff options
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 3 | ||||
| -rw-r--r-- | arch/x86/kvm/mmu.c | 25 | ||||
| -rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 25 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 2 |
4 files changed, 40 insertions, 15 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 65b1ed295698..97215a458e5f 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -602,7 +602,8 @@ unsigned long segment_base(u16 selector); | |||
| 602 | 602 | ||
| 603 | void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu); | 603 | void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu); |
| 604 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | 604 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, |
| 605 | const u8 *new, int bytes); | 605 | const u8 *new, int bytes, |
| 606 | bool guest_initiated); | ||
| 606 | int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); | 607 | int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); |
| 607 | void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); | 608 | void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); |
| 608 | int kvm_mmu_load(struct kvm_vcpu *vcpu); | 609 | int kvm_mmu_load(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index cbac9e4b156f..863baf70506e 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
| @@ -2441,7 +2441,8 @@ static void kvm_mmu_access_page(struct kvm_vcpu *vcpu, gfn_t gfn) | |||
| 2441 | } | 2441 | } |
| 2442 | 2442 | ||
| 2443 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | 2443 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, |
| 2444 | const u8 *new, int bytes) | 2444 | const u8 *new, int bytes, |
| 2445 | bool guest_initiated) | ||
| 2445 | { | 2446 | { |
| 2446 | gfn_t gfn = gpa >> PAGE_SHIFT; | 2447 | gfn_t gfn = gpa >> PAGE_SHIFT; |
| 2447 | struct kvm_mmu_page *sp; | 2448 | struct kvm_mmu_page *sp; |
| @@ -2467,15 +2468,17 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
| 2467 | kvm_mmu_free_some_pages(vcpu); | 2468 | kvm_mmu_free_some_pages(vcpu); |
| 2468 | ++vcpu->kvm->stat.mmu_pte_write; | 2469 | ++vcpu->kvm->stat.mmu_pte_write; |
| 2469 | kvm_mmu_audit(vcpu, "pre pte write"); | 2470 | kvm_mmu_audit(vcpu, "pre pte write"); |
| 2470 | if (gfn == vcpu->arch.last_pt_write_gfn | 2471 | if (guest_initiated) { |
| 2471 | && !last_updated_pte_accessed(vcpu)) { | 2472 | if (gfn == vcpu->arch.last_pt_write_gfn |
| 2472 | ++vcpu->arch.last_pt_write_count; | 2473 | && !last_updated_pte_accessed(vcpu)) { |
| 2473 | if (vcpu->arch.last_pt_write_count >= 3) | 2474 | ++vcpu->arch.last_pt_write_count; |
| 2474 | flooded = 1; | 2475 | if (vcpu->arch.last_pt_write_count >= 3) |
| 2475 | } else { | 2476 | flooded = 1; |
| 2476 | vcpu->arch.last_pt_write_gfn = gfn; | 2477 | } else { |
| 2477 | vcpu->arch.last_pt_write_count = 1; | 2478 | vcpu->arch.last_pt_write_gfn = gfn; |
| 2478 | vcpu->arch.last_pte_updated = NULL; | 2479 | vcpu->arch.last_pt_write_count = 1; |
| 2480 | vcpu->arch.last_pte_updated = NULL; | ||
| 2481 | } | ||
| 2479 | } | 2482 | } |
| 2480 | index = kvm_page_table_hashfn(gfn); | 2483 | index = kvm_page_table_hashfn(gfn); |
| 2481 | bucket = &vcpu->kvm->arch.mmu_page_hash[index]; | 2484 | bucket = &vcpu->kvm->arch.mmu_page_hash[index]; |
| @@ -2615,9 +2618,7 @@ EXPORT_SYMBOL_GPL(kvm_mmu_page_fault); | |||
| 2615 | 2618 | ||
| 2616 | void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva) | 2619 | void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva) |
| 2617 | { | 2620 | { |
| 2618 | spin_lock(&vcpu->kvm->mmu_lock); | ||
| 2619 | vcpu->arch.mmu.invlpg(vcpu, gva); | 2621 | vcpu->arch.mmu.invlpg(vcpu, gva); |
| 2620 | spin_unlock(&vcpu->kvm->mmu_lock); | ||
| 2621 | kvm_mmu_flush_tlb(vcpu); | 2622 | kvm_mmu_flush_tlb(vcpu); |
| 2622 | ++vcpu->stat.invlpg; | 2623 | ++vcpu->stat.invlpg; |
| 2623 | } | 2624 | } |
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index e644d81979b6..d20640154216 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
| @@ -82,6 +82,7 @@ struct shadow_walker { | |||
| 82 | int *ptwrite; | 82 | int *ptwrite; |
| 83 | pfn_t pfn; | 83 | pfn_t pfn; |
| 84 | u64 *sptep; | 84 | u64 *sptep; |
| 85 | gpa_t pte_gpa; | ||
| 85 | }; | 86 | }; |
| 86 | 87 | ||
| 87 | static gfn_t gpte_to_gfn(pt_element_t gpte) | 88 | static gfn_t gpte_to_gfn(pt_element_t gpte) |
| @@ -222,7 +223,7 @@ walk: | |||
| 222 | if (ret) | 223 | if (ret) |
| 223 | goto walk; | 224 | goto walk; |
| 224 | pte |= PT_DIRTY_MASK; | 225 | pte |= PT_DIRTY_MASK; |
| 225 | kvm_mmu_pte_write(vcpu, pte_gpa, (u8 *)&pte, sizeof(pte)); | 226 | kvm_mmu_pte_write(vcpu, pte_gpa, (u8 *)&pte, sizeof(pte), 0); |
| 226 | walker->ptes[walker->level - 1] = pte; | 227 | walker->ptes[walker->level - 1] = pte; |
| 227 | } | 228 | } |
| 228 | 229 | ||
| @@ -468,8 +469,15 @@ static int FNAME(shadow_invlpg_entry)(struct kvm_shadow_walk *_sw, | |||
| 468 | struct kvm_vcpu *vcpu, u64 addr, | 469 | struct kvm_vcpu *vcpu, u64 addr, |
| 469 | u64 *sptep, int level) | 470 | u64 *sptep, int level) |
| 470 | { | 471 | { |
| 472 | struct shadow_walker *sw = | ||
| 473 | container_of(_sw, struct shadow_walker, walker); | ||
| 471 | 474 | ||
| 472 | if (level == PT_PAGE_TABLE_LEVEL) { | 475 | if (level == PT_PAGE_TABLE_LEVEL) { |
| 476 | struct kvm_mmu_page *sp = page_header(__pa(sptep)); | ||
| 477 | |||
| 478 | sw->pte_gpa = (sp->gfn << PAGE_SHIFT); | ||
| 479 | sw->pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t); | ||
| 480 | |||
| 473 | if (is_shadow_present_pte(*sptep)) | 481 | if (is_shadow_present_pte(*sptep)) |
| 474 | rmap_remove(vcpu->kvm, sptep); | 482 | rmap_remove(vcpu->kvm, sptep); |
| 475 | set_shadow_pte(sptep, shadow_trap_nonpresent_pte); | 483 | set_shadow_pte(sptep, shadow_trap_nonpresent_pte); |
| @@ -482,11 +490,26 @@ static int FNAME(shadow_invlpg_entry)(struct kvm_shadow_walk *_sw, | |||
| 482 | 490 | ||
| 483 | static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) | 491 | static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva) |
| 484 | { | 492 | { |
| 493 | pt_element_t gpte; | ||
| 485 | struct shadow_walker walker = { | 494 | struct shadow_walker walker = { |
| 486 | .walker = { .entry = FNAME(shadow_invlpg_entry), }, | 495 | .walker = { .entry = FNAME(shadow_invlpg_entry), }, |
| 496 | .pte_gpa = -1, | ||
| 487 | }; | 497 | }; |
| 488 | 498 | ||
| 499 | spin_lock(&vcpu->kvm->mmu_lock); | ||
| 489 | walk_shadow(&walker.walker, vcpu, gva); | 500 | walk_shadow(&walker.walker, vcpu, gva); |
| 501 | spin_unlock(&vcpu->kvm->mmu_lock); | ||
| 502 | if (walker.pte_gpa == -1) | ||
| 503 | return; | ||
| 504 | if (kvm_read_guest_atomic(vcpu->kvm, walker.pte_gpa, &gpte, | ||
| 505 | sizeof(pt_element_t))) | ||
| 506 | return; | ||
| 507 | if (is_present_pte(gpte) && (gpte & PT_ACCESSED_MASK)) { | ||
| 508 | if (mmu_topup_memory_caches(vcpu)) | ||
| 509 | return; | ||
| 510 | kvm_mmu_pte_write(vcpu, walker.pte_gpa, (const u8 *)&gpte, | ||
| 511 | sizeof(pt_element_t), 0); | ||
| 512 | } | ||
| 490 | } | 513 | } |
| 491 | 514 | ||
| 492 | static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) | 515 | static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 774db00d2db6..ba102879de33 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -2046,7 +2046,7 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
| 2046 | ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes); | 2046 | ret = kvm_write_guest(vcpu->kvm, gpa, val, bytes); |
| 2047 | if (ret < 0) | 2047 | if (ret < 0) |
| 2048 | return 0; | 2048 | return 0; |
| 2049 | kvm_mmu_pte_write(vcpu, gpa, val, bytes); | 2049 | kvm_mmu_pte_write(vcpu, gpa, val, bytes, 1); |
| 2050 | return 1; | 2050 | return 1; |
| 2051 | } | 2051 | } |
| 2052 | 2052 | ||
