diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/x86.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/kvm/x86.c b/drivers/kvm/x86.c index 9db4e3242b62..3b79684a3c0c 100644 --- a/drivers/kvm/x86.c +++ b/drivers/kvm/x86.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/mman.h> | 27 | #include <linux/mman.h> |
28 | #include <linux/highmem.h> | ||
28 | 29 | ||
29 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
30 | #include <asm/msr.h> | 31 | #include <asm/msr.h> |
@@ -1674,6 +1675,31 @@ static int emulator_cmpxchg_emulated(unsigned long addr, | |||
1674 | reported = 1; | 1675 | reported = 1; |
1675 | printk(KERN_WARNING "kvm: emulating exchange as write\n"); | 1676 | printk(KERN_WARNING "kvm: emulating exchange as write\n"); |
1676 | } | 1677 | } |
1678 | #ifndef CONFIG_X86_64 | ||
1679 | /* guests cmpxchg8b have to be emulated atomically */ | ||
1680 | if (bytes == 8) { | ||
1681 | gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); | ||
1682 | struct page *page; | ||
1683 | char *addr; | ||
1684 | u64 val; | ||
1685 | |||
1686 | if (gpa == UNMAPPED_GVA || | ||
1687 | (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) | ||
1688 | goto emul_write; | ||
1689 | |||
1690 | if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK)) | ||
1691 | goto emul_write; | ||
1692 | |||
1693 | val = *(u64 *)new; | ||
1694 | page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); | ||
1695 | addr = kmap_atomic(page, KM_USER0); | ||
1696 | set_64bit((u64 *)(addr + offset_in_page(gpa)), val); | ||
1697 | kunmap_atomic(addr, KM_USER0); | ||
1698 | kvm_release_page_dirty(page); | ||
1699 | } | ||
1700 | emul_write: | ||
1701 | #endif | ||
1702 | |||
1677 | return emulator_write_emulated(addr, new, bytes, vcpu); | 1703 | return emulator_write_emulated(addr, new, bytes, vcpu); |
1678 | } | 1704 | } |
1679 | 1705 | ||