diff options
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 68e121eeccbc..047f6f6ed3f6 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -877,6 +877,27 @@ static int emulator_read_emulated(unsigned long addr, | |||
877 | } | 877 | } |
878 | } | 878 | } |
879 | 879 | ||
880 | static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, | ||
881 | unsigned long val, int bytes) | ||
882 | { | ||
883 | struct kvm_memory_slot *m; | ||
884 | struct page *page; | ||
885 | void *virt; | ||
886 | |||
887 | if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT)) | ||
888 | return 0; | ||
889 | m = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT); | ||
890 | if (!m) | ||
891 | return 0; | ||
892 | page = gfn_to_page(m, gpa >> PAGE_SHIFT); | ||
893 | kvm_mmu_pre_write(vcpu, gpa, bytes); | ||
894 | virt = kmap_atomic(page, KM_USER0); | ||
895 | memcpy(virt + offset_in_page(gpa), &val, bytes); | ||
896 | kunmap_atomic(virt, KM_USER0); | ||
897 | kvm_mmu_post_write(vcpu, gpa, bytes); | ||
898 | return 1; | ||
899 | } | ||
900 | |||
880 | static int emulator_write_emulated(unsigned long addr, | 901 | static int emulator_write_emulated(unsigned long addr, |
881 | unsigned long val, | 902 | unsigned long val, |
882 | unsigned int bytes, | 903 | unsigned int bytes, |
@@ -888,6 +909,9 @@ static int emulator_write_emulated(unsigned long addr, | |||
888 | if (gpa == UNMAPPED_GVA) | 909 | if (gpa == UNMAPPED_GVA) |
889 | return X86EMUL_PROPAGATE_FAULT; | 910 | return X86EMUL_PROPAGATE_FAULT; |
890 | 911 | ||
912 | if (emulator_write_phys(vcpu, gpa, val, bytes)) | ||
913 | return X86EMUL_CONTINUE; | ||
914 | |||
891 | vcpu->mmio_needed = 1; | 915 | vcpu->mmio_needed = 1; |
892 | vcpu->mmio_phys_addr = gpa; | 916 | vcpu->mmio_phys_addr = gpa; |
893 | vcpu->mmio_size = bytes; | 917 | vcpu->mmio_size = bytes; |