aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/kvm/mmu.c5
-rw-r--r--drivers/kvm/paging_tmpl.h31
2 files changed, 13 insertions, 23 deletions
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index d046ba80776..e6616a6c9ce 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -199,6 +199,11 @@ static int is_writeble_pte(unsigned long pte)
199 return pte & PT_WRITABLE_MASK; 199 return pte & PT_WRITABLE_MASK;
200} 200}
201 201
202static int is_dirty_pte(unsigned long pte)
203{
204 return pte & PT_DIRTY_MASK;
205}
206
202static int is_io_pte(unsigned long pte) 207static int is_io_pte(unsigned long pte)
203{ 208{
204 return pte & PT_SHADOW_IO_MARK; 209 return pte & PT_SHADOW_IO_MARK;
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 8e1e4ca6ea4..da36e48fd02 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -144,6 +144,10 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
144 if (walker->level == PT_PAGE_TABLE_LEVEL) { 144 if (walker->level == PT_PAGE_TABLE_LEVEL) {
145 walker->gfn = (*ptep & PT_BASE_ADDR_MASK) 145 walker->gfn = (*ptep & PT_BASE_ADDR_MASK)
146 >> PAGE_SHIFT; 146 >> PAGE_SHIFT;
147 if (write_fault && !is_dirty_pte(*ptep)) {
148 mark_page_dirty(vcpu->kvm, table_gfn);
149 *ptep |= PT_DIRTY_MASK;
150 }
147 break; 151 break;
148 } 152 }
149 153
@@ -153,6 +157,10 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
153 walker->gfn = (*ptep & PT_DIR_BASE_ADDR_MASK) 157 walker->gfn = (*ptep & PT_DIR_BASE_ADDR_MASK)
154 >> PAGE_SHIFT; 158 >> PAGE_SHIFT;
155 walker->gfn += PT_INDEX(addr, PT_PAGE_TABLE_LEVEL); 159 walker->gfn += PT_INDEX(addr, PT_PAGE_TABLE_LEVEL);
160 if (write_fault && !is_dirty_pte(*ptep)) {
161 mark_page_dirty(vcpu->kvm, table_gfn);
162 *ptep |= PT_DIRTY_MASK;
163 }
156 break; 164 break;
157 } 165 }
158 166
@@ -194,12 +202,6 @@ err:
194 return 0; 202 return 0;
195} 203}
196 204
197static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
198 struct guest_walker *walker)
199{
200 mark_page_dirty(kvm, walker->table_gfn[walker->level - 1]);
201}
202
203static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, 205static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
204 u64 *shadow_pte, 206 u64 *shadow_pte,
205 gpa_t gaddr, 207 gpa_t gaddr,
@@ -221,23 +223,6 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
221 __FUNCTION__, *shadow_pte, (u64)gpte, access_bits, 223 __FUNCTION__, *shadow_pte, (u64)gpte, access_bits,
222 write_fault, user_fault, gfn); 224 write_fault, user_fault, gfn);
223 225
224 if (write_fault && !dirty) {
225 pt_element_t *guest_ent, *tmp = NULL;
226
227 if (walker->ptep)
228 guest_ent = walker->ptep;
229 else {
230 tmp = kmap_atomic(walker->page, KM_USER0);
231 guest_ent = &tmp[walker->index];
232 }
233
234 *guest_ent |= PT_DIRTY_MASK;
235 if (!walker->ptep)
236 kunmap_atomic(tmp, KM_USER0);
237 dirty = 1;
238 FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
239 }
240
241 /* 226 /*
242 * We don't set the accessed bit, since we sometimes want to see 227 * 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 228 * whether the guest actually used the pte (in order to detect