aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-03-30 09:54:30 -0400
committerAvi Kivity <avi@qumranet.com>2007-05-03 03:52:28 -0400
commite8207547d2f7b2f557bdb73015c1f74c32474438 (patch)
tree7e5c15bec5cf9ef45a81227b009e6449f5c6d47c
parent954bbbc236afe23b368abdf4942f313a5f6e1d50 (diff)
KVM: Add physical memory aliasing feature
With this, we can specify that accesses to one physical memory range will be remapped to another. This is useful for the vga window at 0xa0000 which is used as a movable window into the (much larger) framebuffer. Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--drivers/kvm/kvm.h9
-rw-r--r--drivers/kvm/kvm_main.c89
-rw-r--r--include/linux/kvm.h10
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
316struct kvm_mem_alias {
317 gfn_t base_gfn;
318 unsigned long npages;
319 gfn_t target_gfn;
320};
321
315struct kvm_memory_slot { 322struct 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
323struct kvm { 330struct 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
849struct 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 */
854static 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
897out:
898 return r;
899}
900
901static 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
915static 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}
862EXPORT_SYMBOL_GPL(gfn_to_memslot); 928
929struct 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
864struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) 935struct 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
36struct 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
37enum kvm_exit_reason { 44enum 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