diff options
author | Avi Kivity <avi@qumranet.com> | 2007-05-31 08:23:35 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-07-16 05:05:44 -0400 |
commit | 0d551bb698e1328f685ae3611c4a4a96f41bef97 (patch) | |
tree | 4668ee0dc19571e4f05443555ec0e807692572e6 /drivers/kvm | |
parent | a18de5a403f9b5010527b2e7b05049b539b4facd (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.h | 37 |
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); |