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 | |
| 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>
| -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); |
