diff options
-rw-r--r-- | drivers/kvm/kvm.h | 9 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 89 | ||||
-rw-r--r-- | include/linux/kvm.h | 10 |
3 files changed, 104 insertions, 4 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 | } |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 728b24cf5d77..da9b23fa4b6c 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -11,7 +11,7 @@ | |||
11 | #include <asm/types.h> | 11 | #include <asm/types.h> |
12 | #include <linux/ioctl.h> | 12 | #include <linux/ioctl.h> |
13 | 13 | ||
14 | #define KVM_API_VERSION 9 | 14 | #define KVM_API_VERSION 10 |
15 | 15 | ||
16 | /* | 16 | /* |
17 | * Architectural interrupt line count, and the size of the bitmap needed | 17 | * Architectural interrupt line count, and the size of the bitmap needed |
@@ -33,6 +33,13 @@ struct kvm_memory_region { | |||
33 | /* for kvm_memory_region::flags */ | 33 | /* for kvm_memory_region::flags */ |
34 | #define KVM_MEM_LOG_DIRTY_PAGES 1UL | 34 | #define KVM_MEM_LOG_DIRTY_PAGES 1UL |
35 | 35 | ||
36 | struct kvm_memory_alias { | ||
37 | __u32 slot; /* this has a different namespace than memory slots */ | ||
38 | __u32 flags; | ||
39 | __u64 guest_phys_addr; | ||
40 | __u64 memory_size; | ||
41 | __u64 target_phys_addr; | ||
42 | }; | ||
36 | 43 | ||
37 | enum kvm_exit_reason { | 44 | enum kvm_exit_reason { |
38 | KVM_EXIT_UNKNOWN = 0, | 45 | KVM_EXIT_UNKNOWN = 0, |
@@ -261,6 +268,7 @@ struct kvm_signal_mask { | |||
261 | */ | 268 | */ |
262 | #define KVM_CREATE_VCPU _IO(KVMIO, 0x41) | 269 | #define KVM_CREATE_VCPU _IO(KVMIO, 0x41) |
263 | #define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log) | 270 | #define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log) |
271 | #define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias) | ||
264 | 272 | ||
265 | /* | 273 | /* |
266 | * ioctls for vcpu fds | 274 | * ioctls for vcpu fds |