diff options
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/kvm.h | 1 | ||||
-rw-r--r-- | drivers/kvm/mmu.c | 21 | ||||
-rw-r--r-- | drivers/kvm/paging_tmpl.h | 9 |
3 files changed, 29 insertions, 2 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 7de948e9e64e..08ffc829f07f 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -346,6 +346,7 @@ struct kvm_vcpu { | |||
346 | 346 | ||
347 | gfn_t last_pt_write_gfn; | 347 | gfn_t last_pt_write_gfn; |
348 | int last_pt_write_count; | 348 | int last_pt_write_count; |
349 | u64 *last_pte_updated; | ||
349 | 350 | ||
350 | struct kvm_guest_debug guest_debug; | 351 | struct kvm_guest_debug guest_debug; |
351 | 352 | ||
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index 069ce83f018e..d347e895736e 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c | |||
@@ -692,6 +692,15 @@ static void kvm_mmu_put_page(struct kvm_mmu_page *page, | |||
692 | mmu_page_remove_parent_pte(page, parent_pte); | 692 | mmu_page_remove_parent_pte(page, parent_pte); |
693 | } | 693 | } |
694 | 694 | ||
695 | static void kvm_mmu_reset_last_pte_updated(struct kvm *kvm) | ||
696 | { | ||
697 | int i; | ||
698 | |||
699 | for (i = 0; i < KVM_MAX_VCPUS; ++i) | ||
700 | if (kvm->vcpus[i]) | ||
701 | kvm->vcpus[i]->last_pte_updated = NULL; | ||
702 | } | ||
703 | |||
695 | static void kvm_mmu_zap_page(struct kvm *kvm, | 704 | static void kvm_mmu_zap_page(struct kvm *kvm, |
696 | struct kvm_mmu_page *page) | 705 | struct kvm_mmu_page *page) |
697 | { | 706 | { |
@@ -717,6 +726,7 @@ static void kvm_mmu_zap_page(struct kvm *kvm, | |||
717 | kvm_mmu_free_page(kvm, page); | 726 | kvm_mmu_free_page(kvm, page); |
718 | } else | 727 | } else |
719 | list_move(&page->link, &kvm->active_mmu_pages); | 728 | list_move(&page->link, &kvm->active_mmu_pages); |
729 | kvm_mmu_reset_last_pte_updated(kvm); | ||
720 | } | 730 | } |
721 | 731 | ||
722 | static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn) | 732 | static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn) |
@@ -1140,6 +1150,13 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, | |||
1140 | offset_in_pte); | 1150 | offset_in_pte); |
1141 | } | 1151 | } |
1142 | 1152 | ||
1153 | static bool last_updated_pte_accessed(struct kvm_vcpu *vcpu) | ||
1154 | { | ||
1155 | u64 *spte = vcpu->last_pte_updated; | ||
1156 | |||
1157 | return !!(spte && (*spte & PT_ACCESSED_MASK)); | ||
1158 | } | ||
1159 | |||
1143 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | 1160 | void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, |
1144 | const u8 *new, int bytes) | 1161 | const u8 *new, int bytes) |
1145 | { | 1162 | { |
@@ -1160,13 +1177,15 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
1160 | 1177 | ||
1161 | pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); | 1178 | pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); |
1162 | kvm_mmu_audit(vcpu, "pre pte write"); | 1179 | kvm_mmu_audit(vcpu, "pre pte write"); |
1163 | if (gfn == vcpu->last_pt_write_gfn) { | 1180 | if (gfn == vcpu->last_pt_write_gfn |
1181 | && !last_updated_pte_accessed(vcpu)) { | ||
1164 | ++vcpu->last_pt_write_count; | 1182 | ++vcpu->last_pt_write_count; |
1165 | if (vcpu->last_pt_write_count >= 3) | 1183 | if (vcpu->last_pt_write_count >= 3) |
1166 | flooded = 1; | 1184 | flooded = 1; |
1167 | } else { | 1185 | } else { |
1168 | vcpu->last_pt_write_gfn = gfn; | 1186 | vcpu->last_pt_write_gfn = gfn; |
1169 | vcpu->last_pt_write_count = 1; | 1187 | vcpu->last_pt_write_count = 1; |
1188 | vcpu->last_pte_updated = NULL; | ||
1170 | } | 1189 | } |
1171 | index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; | 1190 | index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; |
1172 | bucket = &vcpu->kvm->mmu_page_hash[index]; | 1191 | bucket = &vcpu->kvm->mmu_page_hash[index]; |
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index 99ac9b15f773..be0f85231da9 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h | |||
@@ -238,7 +238,12 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, | |||
238 | FNAME(mark_pagetable_dirty)(vcpu->kvm, walker); | 238 | FNAME(mark_pagetable_dirty)(vcpu->kvm, walker); |
239 | } | 239 | } |
240 | 240 | ||
241 | spte = PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK; | 241 | /* |
242 | * We don't set the accessed bit, since we sometimes want to see | ||
243 | * whether the guest actually used the pte (in order to detect | ||
244 | * demand paging). | ||
245 | */ | ||
246 | spte = PT_PRESENT_MASK | PT_DIRTY_MASK; | ||
242 | spte |= gpte & PT64_NX_MASK; | 247 | spte |= gpte & PT64_NX_MASK; |
243 | if (!dirty) | 248 | if (!dirty) |
244 | access_bits &= ~PT_WRITABLE_MASK; | 249 | access_bits &= ~PT_WRITABLE_MASK; |
@@ -291,6 +296,8 @@ unshadowed: | |||
291 | page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); | 296 | page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); |
292 | if (!was_rmapped) | 297 | if (!was_rmapped) |
293 | rmap_add(vcpu, shadow_pte); | 298 | rmap_add(vcpu, shadow_pte); |
299 | if (!ptwrite || !*ptwrite) | ||
300 | vcpu->last_pte_updated = shadow_pte; | ||
294 | } | 301 | } |
295 | 302 | ||
296 | static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, | 303 | static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, |