aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-10-11 06:32:30 -0400
committerAvi Kivity <avi@qumranet.com>2008-01-30 10:52:51 -0500
commite3c5e7ec9efe0ebd47fa812cc86f01c51905edf6 (patch)
treeb049d19c4a1a417977a286781d98301b39bea4f2
parent4a4c99248713e878e1e2880015d01049aec805f3 (diff)
KVM: Move guest pte dirty bit management to the guest pagetable walker
This is more consistent with the accessed bit management, and makes the dirty bit available earlier for other purposes. Signed-off-by: Avi Kivity <avi@qumranet.com>
-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 d046ba807763..e6616a6c9cef 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 8e1e4ca6ea4e..da36e48fd026 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