Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 197666
b: refs/heads/master
c: daea3e7
h: refs/heads/master
v: v3
  • Loading branch information
Avi Kivity committed May 17, 2010
1 parent 6e1fad2 commit 0d11670
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 72016f3a4221799a0b1fdf443ef6e29db572a9bb
refs/heads/master: daea3e73cb4ac971bee97f333ae027861d00fc0b
69 changes: 48 additions & 21 deletions trunk/arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -3291,41 +3291,68 @@ int emulator_write_emulated(unsigned long addr,
}
EXPORT_SYMBOL_GPL(emulator_write_emulated);

#define CMPXCHG_TYPE(t, ptr, old, new) \
(cmpxchg((t *)(ptr), *(t *)(old), *(t *)(new)) == *(t *)(old))

#ifdef CONFIG_X86_64
# define CMPXCHG64(ptr, old, new) CMPXCHG_TYPE(u64, ptr, old, new)
#else
# define CMPXCHG64(ptr, old, new) \
(cmpxchg64((u64 *)(ptr), *(u64 *)(old), *(u *)(new)) == *(u64 *)(old))
#endif

static int emulator_cmpxchg_emulated(unsigned long addr,
const void *old,
const void *new,
unsigned int bytes,
struct kvm_vcpu *vcpu)
{
printk_once(KERN_WARNING "kvm: emulating exchange as write\n");
#ifndef CONFIG_X86_64
/* guests cmpxchg8b have to be emulated atomically */
if (bytes == 8) {
gpa_t gpa;
struct page *page;
char *kaddr;
u64 val;
gpa_t gpa;
struct page *page;
char *kaddr;
bool exchanged;

gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL);
/* guests cmpxchg8b have to be emulated atomically */
if (bytes > 8 || (bytes & (bytes - 1)))
goto emul_write;

if (gpa == UNMAPPED_GVA ||
(gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
goto emul_write;
gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL);

if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
goto emul_write;
if (gpa == UNMAPPED_GVA ||
(gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
goto emul_write;

val = *(u64 *)new;
if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
goto emul_write;

page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);

kaddr = kmap_atomic(page, KM_USER0);
set_64bit((u64 *)(kaddr + offset_in_page(gpa)), val);
kunmap_atomic(kaddr, KM_USER0);
kvm_release_page_dirty(page);
kaddr = kmap_atomic(page, KM_USER0);
kaddr += offset_in_page(gpa);
switch (bytes) {
case 1:
exchanged = CMPXCHG_TYPE(u8, kaddr, old, new);
break;
case 2:
exchanged = CMPXCHG_TYPE(u16, kaddr, old, new);
break;
case 4:
exchanged = CMPXCHG_TYPE(u32, kaddr, old, new);
break;
case 8:
exchanged = CMPXCHG64(kaddr, old, new);
break;
default:
BUG();
}
kunmap_atomic(kaddr, KM_USER0);
kvm_release_page_dirty(page);

if (!exchanged)
return X86EMUL_CMPXCHG_FAILED;

emul_write:
#endif
printk_once(KERN_WARNING "kvm: emulating exchange as write\n");

return emulator_write_emulated(addr, new, bytes, vcpu);
}
Expand Down

0 comments on commit 0d11670

Please sign in to comment.