aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/kvm_main.c
diff options
context:
space:
mode:
authorIzik Eidus <izike@qumranet.com>2007-10-09 13:20:39 -0400
committerAvi Kivity <avi@qumranet.com>2008-01-30 10:52:51 -0500
commit6fc138d2278078990f597cb1f62fde9e5b458f96 (patch)
tree176026316843a4e47b8271f0e84a03f8807ecb64 /drivers/kvm/kvm_main.c
parentd77c26fce93d07802db97498959587eb9347b31d (diff)
KVM: Support assigning userspace memory to the guest
Instead of having the kernel allocate memory to the guest, let userspace allocate it and pass the address to the kernel. This is required for s390 support, but also enables features like memory sharing and using hugetlbfs backed memory. Signed-off-by: Izik Eidus <izike@qumranet.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r--drivers/kvm/kvm_main.c81
1 files changed, 70 insertions, 11 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index a1983d2d5b8f..22b143feb66d 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -40,6 +40,7 @@
40#include <linux/anon_inodes.h> 40#include <linux/anon_inodes.h>
41#include <linux/profile.h> 41#include <linux/profile.h>
42#include <linux/kvm_para.h> 42#include <linux/kvm_para.h>
43#include <linux/pagemap.h>
43 44
44#include <asm/processor.h> 45#include <asm/processor.h>
45#include <asm/msr.h> 46#include <asm/msr.h>
@@ -300,19 +301,40 @@ static struct kvm *kvm_create_vm(void)
300 return kvm; 301 return kvm;
301} 302}
302 303
304static void kvm_free_userspace_physmem(struct kvm_memory_slot *free)
305{
306 int i;
307
308 for (i = 0; i < free->npages; ++i) {
309 if (free->phys_mem[i]) {
310 if (!PageReserved(free->phys_mem[i]))
311 SetPageDirty(free->phys_mem[i]);
312 page_cache_release(free->phys_mem[i]);
313 }
314 }
315}
316
317static void kvm_free_kernel_physmem(struct kvm_memory_slot *free)
318{
319 int i;
320
321 for (i = 0; i < free->npages; ++i)
322 if (free->phys_mem[i])
323 __free_page(free->phys_mem[i]);
324}
325
303/* 326/*
304 * Free any memory in @free but not in @dont. 327 * Free any memory in @free but not in @dont.
305 */ 328 */
306static void kvm_free_physmem_slot(struct kvm_memory_slot *free, 329static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
307 struct kvm_memory_slot *dont) 330 struct kvm_memory_slot *dont)
308{ 331{
309 int i;
310
311 if (!dont || free->phys_mem != dont->phys_mem) 332 if (!dont || free->phys_mem != dont->phys_mem)
312 if (free->phys_mem) { 333 if (free->phys_mem) {
313 for (i = 0; i < free->npages; ++i) 334 if (free->user_alloc)
314 if (free->phys_mem[i]) 335 kvm_free_userspace_physmem(free);
315 __free_page(free->phys_mem[i]); 336 else
337 kvm_free_kernel_physmem(free);
316 vfree(free->phys_mem); 338 vfree(free->phys_mem);
317 } 339 }
318 if (!dont || free->rmap != dont->rmap) 340 if (!dont || free->rmap != dont->rmap)
@@ -652,7 +674,9 @@ EXPORT_SYMBOL_GPL(fx_init);
652 * Discontiguous memory is allowed, mostly for framebuffers. 674 * Discontiguous memory is allowed, mostly for framebuffers.
653 */ 675 */
654static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, 676static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
655 struct kvm_memory_region *mem) 677 struct
678 kvm_userspace_memory_region *mem,
679 int user_alloc)
656{ 680{
657 int r; 681 int r;
658 gfn_t base_gfn; 682 gfn_t base_gfn;
@@ -728,11 +752,27 @@ static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
728 752
729 memset(new.phys_mem, 0, npages * sizeof(struct page *)); 753 memset(new.phys_mem, 0, npages * sizeof(struct page *));
730 memset(new.rmap, 0, npages * sizeof(*new.rmap)); 754 memset(new.rmap, 0, npages * sizeof(*new.rmap));
731 for (i = 0; i < npages; ++i) { 755 if (user_alloc) {
732 new.phys_mem[i] = alloc_page(GFP_HIGHUSER 756 unsigned long pages_num;
733 | __GFP_ZERO); 757
734 if (!new.phys_mem[i]) 758 new.user_alloc = 1;
759 down_read(&current->mm->mmap_sem);
760
761 pages_num = get_user_pages(current, current->mm,
762 mem->userspace_addr,
763 npages, 1, 1, new.phys_mem,
764 NULL);
765
766 up_read(&current->mm->mmap_sem);
767 if (pages_num != npages)
735 goto out_unlock; 768 goto out_unlock;
769 } else {
770 for (i = 0; i < npages; ++i) {
771 new.phys_mem[i] = alloc_page(GFP_HIGHUSER
772 | __GFP_ZERO);
773 if (!new.phys_mem[i])
774 goto out_unlock;
775 }
736 } 776 }
737 } 777 }
738 778
@@ -3108,11 +3148,29 @@ static long kvm_vm_ioctl(struct file *filp,
3108 break; 3148 break;
3109 case KVM_SET_MEMORY_REGION: { 3149 case KVM_SET_MEMORY_REGION: {
3110 struct kvm_memory_region kvm_mem; 3150 struct kvm_memory_region kvm_mem;
3151 struct kvm_userspace_memory_region kvm_userspace_mem;
3111 3152
3112 r = -EFAULT; 3153 r = -EFAULT;
3113 if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) 3154 if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
3114 goto out; 3155 goto out;
3115 r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_mem); 3156 kvm_userspace_mem.slot = kvm_mem.slot;
3157 kvm_userspace_mem.flags = kvm_mem.flags;
3158 kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
3159 kvm_userspace_mem.memory_size = kvm_mem.memory_size;
3160 r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
3161 if (r)
3162 goto out;
3163 break;
3164 }
3165 case KVM_SET_USER_MEMORY_REGION: {
3166 struct kvm_userspace_memory_region kvm_userspace_mem;
3167
3168 r = -EFAULT;
3169 if (copy_from_user(&kvm_userspace_mem, argp,
3170 sizeof kvm_userspace_mem))
3171 goto out;
3172
3173 r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 1);
3116 if (r) 3174 if (r)
3117 goto out; 3175 goto out;
3118 break; 3176 break;
@@ -3332,6 +3390,7 @@ static long kvm_dev_ioctl(struct file *filp,
3332 case KVM_CAP_IRQCHIP: 3390 case KVM_CAP_IRQCHIP:
3333 case KVM_CAP_HLT: 3391 case KVM_CAP_HLT:
3334 case KVM_CAP_MMU_SHADOW_CACHE_CONTROL: 3392 case KVM_CAP_MMU_SHADOW_CACHE_CONTROL:
3393 case KVM_CAP_USER_MEMORY:
3335 r = 1; 3394 r = 1;
3336 break; 3395 break;
3337 default: 3396 default: