aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-01-05 19:36:44 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2007-01-06 02:55:25 -0500
commitda4a00f002239f72b0d7d0eeaa3b60100e2b1438 (patch)
tree7c7e72ea1fd48025c029429b413e127a3a580c10
parent815af8d42ee3f844c0ceaf2104bd9c6a0bb1e26c (diff)
[PATCH] KVM: MMU: Support emulated writes into RAM
As the mmu write protects guest page table, we emulate those writes. Since they are not mmio, there is no need to go to userspace to perform them. So, perform the writes in the kernel if possible, and notify the mmu about them so it can take the approriate action. Signed-off-by: Avi Kivity <avi@qumranet.com> Acked-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/kvm/kvm.h3
-rw-r--r--drivers/kvm/kvm_main.c24
-rw-r--r--drivers/kvm/mmu.c9
3 files changed, 36 insertions, 0 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 58b9deb0bc0e..b7068ecd7765 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -448,6 +448,9 @@ int kvm_write_guest(struct kvm_vcpu *vcpu,
448 448
449unsigned long segment_base(u16 selector); 449unsigned long segment_base(u16 selector);
450 450
451void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
452void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
453
451static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn) 454static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn)
452{ 455{
453 struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn); 456 struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
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
880static 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
880static int emulator_write_emulated(unsigned long addr, 901static 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;
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index ceae25bfd4b5..bce7eb21f739 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -956,6 +956,15 @@ int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
956 return init_kvm_mmu(vcpu); 956 return init_kvm_mmu(vcpu);
957} 957}
958 958
959void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
960{
961 pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes);
962}
963
964void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
965{
966}
967
959static void free_mmu_pages(struct kvm_vcpu *vcpu) 968static void free_mmu_pages(struct kvm_vcpu *vcpu)
960{ 969{
961 while (!list_empty(&vcpu->free_pages)) { 970 while (!list_empty(&vcpu->free_pages)) {