diff options
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/kvm.h | 9 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 89 |
2 files changed, 95 insertions, 3 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index d19985a5508a..fceeb840a255 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h | |||
@@ -51,6 +51,7 @@ | |||
51 | #define UNMAPPED_GVA (~(gpa_t)0) | 51 | #define UNMAPPED_GVA (~(gpa_t)0) |
52 | 52 | ||
53 | #define KVM_MAX_VCPUS 1 | 53 | #define KVM_MAX_VCPUS 1 |
54 | #define KVM_ALIAS_SLOTS 4 | ||
54 | #define KVM_MEMORY_SLOTS 4 | 55 | #define KVM_MEMORY_SLOTS 4 |
55 | #define KVM_NUM_MMU_PAGES 256 | 56 | #define KVM_NUM_MMU_PAGES 256 |
56 | #define KVM_MIN_FREE_MMU_PAGES 5 | 57 | #define KVM_MIN_FREE_MMU_PAGES 5 |
@@ -312,6 +313,12 @@ struct kvm_vcpu { | |||
312 | struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES]; | 313 | struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES]; |
313 | }; | 314 | }; |
314 | 315 | ||
316 | struct kvm_mem_alias { | ||
317 | gfn_t base_gfn; | ||
318 | unsigned long npages; | ||
319 | gfn_t target_gfn; | ||
320 | }; | ||
321 | |||
315 | struct kvm_memory_slot { | 322 | struct kvm_memory_slot { |
316 | gfn_t base_gfn; | 323 | gfn_t base_gfn; |
317 | unsigned long npages; | 324 | unsigned long npages; |
@@ -322,6 +329,8 @@ struct kvm_memory_slot { | |||
322 | 329 | ||
323 | struct kvm { | 330 | struct kvm { |
324 | spinlock_t lock; /* protects everything except vcpus */ | 331 | spinlock_t lock; /* protects everything except vcpus */ |
332 | int naliases; | ||
333 | struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; | ||
325 | int nmemslots; | 334 | int nmemslots; |
326 | struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS]; | 335 | struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS]; |
327 | /* | 336 | /* |
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index a0ec5dda3305..e495855727e2 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -846,7 +846,73 @@ out: | |||
846 | return r; | 846 | return r; |
847 | } | 847 | } |
848 | 848 | ||
849 | struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) | 849 | /* |
850 | * Set a new alias region. Aliases map a portion of physical memory into | ||
851 | * another portion. This is useful for memory windows, for example the PC | ||
852 | * VGA region. | ||
853 | */ | ||
854 | static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, | ||
855 | struct kvm_memory_alias *alias) | ||
856 | { | ||
857 | int r, n; | ||
858 | struct kvm_mem_alias *p; | ||
859 | |||
860 | r = -EINVAL; | ||
861 | /* General sanity checks */ | ||
862 | if (alias->memory_size & (PAGE_SIZE - 1)) | ||
863 | goto out; | ||
864 | if (alias->guest_phys_addr & (PAGE_SIZE - 1)) | ||
865 | goto out; | ||
866 | if (alias->slot >= KVM_ALIAS_SLOTS) | ||
867 | goto out; | ||
868 | if (alias->guest_phys_addr + alias->memory_size | ||
869 | < alias->guest_phys_addr) | ||
870 | goto out; | ||
871 | if (alias->target_phys_addr + alias->memory_size | ||
872 | < alias->target_phys_addr) | ||
873 | goto out; | ||
874 | |||
875 | spin_lock(&kvm->lock); | ||
876 | |||
877 | p = &kvm->aliases[alias->slot]; | ||
878 | p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; | ||
879 | p->npages = alias->memory_size >> PAGE_SHIFT; | ||
880 | p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; | ||
881 | |||
882 | for (n = KVM_ALIAS_SLOTS; n > 0; --n) | ||
883 | if (kvm->aliases[n - 1].npages) | ||
884 | break; | ||
885 | kvm->naliases = n; | ||
886 | |||
887 | spin_unlock(&kvm->lock); | ||
888 | |||
889 | vcpu_load(&kvm->vcpus[0]); | ||
890 | spin_lock(&kvm->lock); | ||
891 | kvm_mmu_zap_all(&kvm->vcpus[0]); | ||
892 | spin_unlock(&kvm->lock); | ||
893 | vcpu_put(&kvm->vcpus[0]); | ||
894 | |||
895 | return 0; | ||
896 | |||
897 | out: | ||
898 | return r; | ||
899 | } | ||
900 | |||
901 | static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) | ||
902 | { | ||
903 | int i; | ||
904 | struct kvm_mem_alias *alias; | ||
905 | |||
906 | for (i = 0; i < kvm->naliases; ++i) { | ||
907 | alias = &kvm->aliases[i]; | ||
908 | if (gfn >= alias->base_gfn | ||
909 | && gfn < alias->base_gfn + alias->npages) | ||
910 | return alias->target_gfn + gfn - alias->base_gfn; | ||
911 | } | ||
912 | return gfn; | ||
913 | } | ||
914 | |||
915 | static struct kvm_memory_slot *__gfn_to_memslot(struct kvm *kvm, gfn_t gfn) | ||
850 | { | 916 | { |
851 | int i; | 917 | int i; |
852 | 918 | ||
@@ -859,13 +925,19 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) | |||
859 | } | 925 | } |
860 | return NULL; | 926 | return NULL; |
861 | } | 927 | } |
862 | EXPORT_SYMBOL_GPL(gfn_to_memslot); | 928 | |
929 | struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) | ||
930 | { | ||
931 | gfn = unalias_gfn(kvm, gfn); | ||
932 | return __gfn_to_memslot(kvm, gfn); | ||
933 | } | ||
863 | 934 | ||
864 | struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) | 935 | struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) |
865 | { | 936 | { |
866 | struct kvm_memory_slot *slot; | 937 | struct kvm_memory_slot *slot; |
867 | 938 | ||
868 | slot = gfn_to_memslot(kvm, gfn); | 939 | gfn = unalias_gfn(kvm, gfn); |
940 | slot = __gfn_to_memslot(kvm, gfn); | ||
869 | if (!slot) | 941 | if (!slot) |
870 | return NULL; | 942 | return NULL; |
871 | return slot->phys_mem[gfn - slot->base_gfn]; | 943 | return slot->phys_mem[gfn - slot->base_gfn]; |
@@ -2512,6 +2584,17 @@ static long kvm_vm_ioctl(struct file *filp, | |||
2512 | goto out; | 2584 | goto out; |
2513 | break; | 2585 | break; |
2514 | } | 2586 | } |
2587 | case KVM_SET_MEMORY_ALIAS: { | ||
2588 | struct kvm_memory_alias alias; | ||
2589 | |||
2590 | r = -EFAULT; | ||
2591 | if (copy_from_user(&alias, argp, sizeof alias)) | ||
2592 | goto out; | ||
2593 | r = kvm_vm_ioctl_set_memory_alias(kvm, &alias); | ||
2594 | if (r) | ||
2595 | goto out; | ||
2596 | break; | ||
2597 | } | ||
2515 | default: | 2598 | default: |
2516 | ; | 2599 | ; |
2517 | } | 2600 | } |