aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-05-31 08:23:35 -0400
committerAvi Kivity <avi@qumranet.com>2007-07-16 05:05:44 -0400
commit0d551bb698e1328f685ae3611c4a4a96f41bef97 (patch)
tree4668ee0dc19571e4f05443555ec0e807692572e6 /drivers/kvm
parenta18de5a403f9b5010527b2e7b05049b539b4facd (diff)
KVM: Make shadow pte updates atomic
With guest smp, a second vcpu might see partial updates when the first vcpu services a page fault. So delay all updates until we have figured out what the pte should look like. Note that on i386, this is still not completely atomic as a 64-bit write will be split into two on a 32-bit machine. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm')
-rw-r--r--drivers/kvm/paging_tmpl.h37
1 files changed, 20 insertions, 17 deletions
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 35f264f346d8..397a4039eaad 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -205,11 +205,12 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
205{ 205{
206 hpa_t paddr; 206 hpa_t paddr;
207 int dirty = *gpte & PT_DIRTY_MASK; 207 int dirty = *gpte & PT_DIRTY_MASK;
208 int was_rmapped = is_rmap_pte(*shadow_pte); 208 u64 spte = *shadow_pte;
209 int was_rmapped = is_rmap_pte(spte);
209 210
210 pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d" 211 pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d"
211 " user_fault %d gfn %lx\n", 212 " user_fault %d gfn %lx\n",
212 __FUNCTION__, *shadow_pte, (u64)*gpte, access_bits, 213 __FUNCTION__, spte, (u64)*gpte, access_bits,
213 write_fault, user_fault, gfn); 214 write_fault, user_fault, gfn);
214 215
215 if (write_fault && !dirty) { 216 if (write_fault && !dirty) {
@@ -218,34 +219,35 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
218 FNAME(mark_pagetable_dirty)(vcpu->kvm, walker); 219 FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
219 } 220 }
220 221
221 *shadow_pte |= *gpte & PT_PTE_COPY_MASK; 222 spte |= *gpte & PT_PTE_COPY_MASK;
222 *shadow_pte |= access_bits << PT_SHADOW_BITS_OFFSET; 223 spte |= access_bits << PT_SHADOW_BITS_OFFSET;
223 if (!dirty) 224 if (!dirty)
224 access_bits &= ~PT_WRITABLE_MASK; 225 access_bits &= ~PT_WRITABLE_MASK;
225 226
226 paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK); 227 paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK);
227 228
228 *shadow_pte |= PT_PRESENT_MASK; 229 spte |= PT_PRESENT_MASK;
229 if (access_bits & PT_USER_MASK) 230 if (access_bits & PT_USER_MASK)
230 *shadow_pte |= PT_USER_MASK; 231 spte |= PT_USER_MASK;
231 232
232 if (is_error_hpa(paddr)) { 233 if (is_error_hpa(paddr)) {
233 *shadow_pte |= gaddr; 234 spte |= gaddr;
234 *shadow_pte |= PT_SHADOW_IO_MARK; 235 spte |= PT_SHADOW_IO_MARK;
235 *shadow_pte &= ~PT_PRESENT_MASK; 236 spte &= ~PT_PRESENT_MASK;
237 *shadow_pte = spte;
236 return; 238 return;
237 } 239 }
238 240
239 *shadow_pte |= paddr; 241 spte |= paddr;
240 242
241 if (!write_fault && (*shadow_pte & PT_SHADOW_USER_MASK) && 243 if (!write_fault && (spte & PT_SHADOW_USER_MASK) &&
242 !(*shadow_pte & PT_USER_MASK)) { 244 !(spte & PT_USER_MASK)) {
243 /* 245 /*
244 * If supervisor write protect is disabled, we shadow kernel 246 * If supervisor write protect is disabled, we shadow kernel
245 * pages as user pages so we can trap the write access. 247 * pages as user pages so we can trap the write access.
246 */ 248 */
247 *shadow_pte |= PT_USER_MASK; 249 spte |= PT_USER_MASK;
248 *shadow_pte &= ~PT_WRITABLE_MASK; 250 spte &= ~PT_WRITABLE_MASK;
249 access_bits &= ~PT_WRITABLE_MASK; 251 access_bits &= ~PT_WRITABLE_MASK;
250 } 252 }
251 253
@@ -253,7 +255,7 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
253 || (write_fault && !is_write_protection(vcpu) && !user_fault)) { 255 || (write_fault && !is_write_protection(vcpu) && !user_fault)) {
254 struct kvm_mmu_page *shadow; 256 struct kvm_mmu_page *shadow;
255 257
256 *shadow_pte |= PT_WRITABLE_MASK; 258 spte |= PT_WRITABLE_MASK;
257 if (user_fault) { 259 if (user_fault) {
258 mmu_unshadow(vcpu, gfn); 260 mmu_unshadow(vcpu, gfn);
259 goto unshadowed; 261 goto unshadowed;
@@ -264,8 +266,8 @@ static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
264 pgprintk("%s: found shadow page for %lx, marking ro\n", 266 pgprintk("%s: found shadow page for %lx, marking ro\n",
265 __FUNCTION__, gfn); 267 __FUNCTION__, gfn);
266 access_bits &= ~PT_WRITABLE_MASK; 268 access_bits &= ~PT_WRITABLE_MASK;
267 if (is_writeble_pte(*shadow_pte)) { 269 if (is_writeble_pte(spte)) {
268 *shadow_pte &= ~PT_WRITABLE_MASK; 270 spte &= ~PT_WRITABLE_MASK;
269 kvm_arch_ops->tlb_flush(vcpu); 271 kvm_arch_ops->tlb_flush(vcpu);
270 } 272 }
271 if (write_fault) 273 if (write_fault)
@@ -278,6 +280,7 @@ unshadowed:
278 if (access_bits & PT_WRITABLE_MASK) 280 if (access_bits & PT_WRITABLE_MASK)
279 mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT); 281 mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT);
280 282
283 *shadow_pte = spte;
281 page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); 284 page_header_update_slot(vcpu->kvm, shadow_pte, gaddr);
282 if (!was_rmapped) 285 if (!was_rmapped)
283 rmap_add(vcpu, shadow_pte); 286 rmap_add(vcpu, shadow_pte);