aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2010-03-15 07:59:55 -0400
committerAvi Kivity <avi@redhat.com>2010-05-17 05:15:40 -0400
commit4a5f48f666ccc4ffdbc54241d9cab06806ed7922 (patch)
tree91a1851ad84d2380a5cb9c1e9223d44ffc87365e /arch
parentdaea3e73cb4ac971bee97f333ae027861d00fc0b (diff)
KVM: Don't follow an atomic operation by a non-atomic one
Currently emulated atomic operations are immediately followed by a non-atomic operation, so that kvm_mmu_pte_write() can be invoked. This updates the mmu but undoes the whole point of doing things atomically. Fix by only performing the atomic operation and the mmu update, and avoiding the non-atomic write. Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kvm/x86.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 855f3ea9edd1..dd4a7ad63aff 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3234,7 +3234,8 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
3234static int emulator_write_emulated_onepage(unsigned long addr, 3234static int emulator_write_emulated_onepage(unsigned long addr,
3235 const void *val, 3235 const void *val,
3236 unsigned int bytes, 3236 unsigned int bytes,
3237 struct kvm_vcpu *vcpu) 3237 struct kvm_vcpu *vcpu,
3238 bool mmu_only)
3238{ 3239{
3239 gpa_t gpa; 3240 gpa_t gpa;
3240 u32 error_code; 3241 u32 error_code;
@@ -3250,6 +3251,10 @@ static int emulator_write_emulated_onepage(unsigned long addr,
3250 if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) 3251 if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
3251 goto mmio; 3252 goto mmio;
3252 3253
3254 if (mmu_only) {
3255 kvm_mmu_pte_write(vcpu, gpa, val, bytes, 1);
3256 return X86EMUL_CONTINUE;
3257 }
3253 if (emulator_write_phys(vcpu, gpa, val, bytes)) 3258 if (emulator_write_phys(vcpu, gpa, val, bytes))
3254 return X86EMUL_CONTINUE; 3259 return X86EMUL_CONTINUE;
3255 3260
@@ -3270,24 +3275,35 @@ mmio:
3270 return X86EMUL_CONTINUE; 3275 return X86EMUL_CONTINUE;
3271} 3276}
3272 3277
3273int emulator_write_emulated(unsigned long addr, 3278int __emulator_write_emulated(unsigned long addr,
3274 const void *val, 3279 const void *val,
3275 unsigned int bytes, 3280 unsigned int bytes,
3276 struct kvm_vcpu *vcpu) 3281 struct kvm_vcpu *vcpu,
3282 bool mmu_only)
3277{ 3283{
3278 /* Crossing a page boundary? */ 3284 /* Crossing a page boundary? */
3279 if (((addr + bytes - 1) ^ addr) & PAGE_MASK) { 3285 if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
3280 int rc, now; 3286 int rc, now;
3281 3287
3282 now = -addr & ~PAGE_MASK; 3288 now = -addr & ~PAGE_MASK;
3283 rc = emulator_write_emulated_onepage(addr, val, now, vcpu); 3289 rc = emulator_write_emulated_onepage(addr, val, now, vcpu,
3290 mmu_only);
3284 if (rc != X86EMUL_CONTINUE) 3291 if (rc != X86EMUL_CONTINUE)
3285 return rc; 3292 return rc;
3286 addr += now; 3293 addr += now;
3287 val += now; 3294 val += now;
3288 bytes -= now; 3295 bytes -= now;
3289 } 3296 }
3290 return emulator_write_emulated_onepage(addr, val, bytes, vcpu); 3297 return emulator_write_emulated_onepage(addr, val, bytes, vcpu,
3298 mmu_only);
3299}
3300
3301int emulator_write_emulated(unsigned long addr,
3302 const void *val,
3303 unsigned int bytes,
3304 struct kvm_vcpu *vcpu)
3305{
3306 return __emulator_write_emulated(addr, val, bytes, vcpu, false);
3291} 3307}
3292EXPORT_SYMBOL_GPL(emulator_write_emulated); 3308EXPORT_SYMBOL_GPL(emulator_write_emulated);
3293 3309
@@ -3351,6 +3367,8 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
3351 if (!exchanged) 3367 if (!exchanged)
3352 return X86EMUL_CMPXCHG_FAILED; 3368 return X86EMUL_CMPXCHG_FAILED;
3353 3369
3370 return __emulator_write_emulated(addr, new, bytes, vcpu, true);
3371
3354emul_write: 3372emul_write:
3355 printk_once(KERN_WARNING "kvm: emulating exchange as write\n"); 3373 printk_once(KERN_WARNING "kvm: emulating exchange as write\n");
3356 3374
@@ -4005,7 +4023,7 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
4005 4023
4006 kvm_x86_ops->patch_hypercall(vcpu, instruction); 4024 kvm_x86_ops->patch_hypercall(vcpu, instruction);
4007 4025
4008 return emulator_write_emulated(rip, instruction, 3, vcpu); 4026 return __emulator_write_emulated(rip, instruction, 3, vcpu, false);
4009} 4027}
4010 4028
4011static u64 mk_cr_64(u64 curr_cr, u32 new_val) 4029static u64 mk_cr_64(u64 curr_cr, u32 new_val)