#include <linux/anon_inodes.h>
 #include <linux/profile.h>
 #include <linux/kvm_para.h>
+#include <linux/pagemap.h>
 
 #include <asm/processor.h>
 #include <asm/msr.h>
        return kvm;
 }
 
+static void kvm_free_userspace_physmem(struct kvm_memory_slot *free)
+{
+       int i;
+
+       for (i = 0; i < free->npages; ++i) {
+               if (free->phys_mem[i]) {
+                       if (!PageReserved(free->phys_mem[i]))
+                               SetPageDirty(free->phys_mem[i]);
+                       page_cache_release(free->phys_mem[i]);
+               }
+       }
+}
+
+static void kvm_free_kernel_physmem(struct kvm_memory_slot *free)
+{
+       int i;
+
+       for (i = 0; i < free->npages; ++i)
+               if (free->phys_mem[i])
+                       __free_page(free->phys_mem[i]);
+}
+
 /*
  * Free any memory in @free but not in @dont.
  */
 static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
                                  struct kvm_memory_slot *dont)
 {
-       int i;
-
        if (!dont || free->phys_mem != dont->phys_mem)
                if (free->phys_mem) {
-                       for (i = 0; i < free->npages; ++i)
-                               if (free->phys_mem[i])
-                                       __free_page(free->phys_mem[i]);
+                       if (free->user_alloc)
+                               kvm_free_userspace_physmem(free);
+                       else
+                               kvm_free_kernel_physmem(free);
                        vfree(free->phys_mem);
                }
        if (!dont || free->rmap != dont->rmap)
  * Discontiguous memory is allowed, mostly for framebuffers.
  */
 static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
-                                         struct kvm_memory_region *mem)
+                                         struct
+                                         kvm_userspace_memory_region *mem,
+                                         int user_alloc)
 {
        int r;
        gfn_t base_gfn;
 
                memset(new.phys_mem, 0, npages * sizeof(struct page *));
                memset(new.rmap, 0, npages * sizeof(*new.rmap));
-               for (i = 0; i < npages; ++i) {
-                       new.phys_mem[i] = alloc_page(GFP_HIGHUSER
-                                                    | __GFP_ZERO);
-                       if (!new.phys_mem[i])
+               if (user_alloc) {
+                       unsigned long pages_num;
+
+                       new.user_alloc = 1;
+                       down_read(¤t->mm->mmap_sem);
+
+                       pages_num = get_user_pages(current, current->mm,
+                                                  mem->userspace_addr,
+                                                  npages, 1, 1, new.phys_mem,
+                                                  NULL);
+
+                       up_read(¤t->mm->mmap_sem);
+                       if (pages_num != npages)
                                goto out_unlock;
+               } else {
+                       for (i = 0; i < npages; ++i) {
+                               new.phys_mem[i] = alloc_page(GFP_HIGHUSER
+                                                            | __GFP_ZERO);
+                               if (!new.phys_mem[i])
+                                       goto out_unlock;
+                       }
                }
        }
 
                break;
        case KVM_SET_MEMORY_REGION: {
                struct kvm_memory_region kvm_mem;
+               struct kvm_userspace_memory_region kvm_userspace_mem;
 
                r = -EFAULT;
                if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
                        goto out;
-               r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_mem);
+               kvm_userspace_mem.slot = kvm_mem.slot;
+               kvm_userspace_mem.flags = kvm_mem.flags;
+               kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
+               kvm_userspace_mem.memory_size = kvm_mem.memory_size;
+               r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
+               if (r)
+                       goto out;
+               break;
+       }
+       case KVM_SET_USER_MEMORY_REGION: {
+               struct kvm_userspace_memory_region kvm_userspace_mem;
+
+               r = -EFAULT;
+               if (copy_from_user(&kvm_userspace_mem, argp,
+                                               sizeof kvm_userspace_mem))
+                       goto out;
+
+               r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 1);
                if (r)
                        goto out;
                break;
                case KVM_CAP_IRQCHIP:
                case KVM_CAP_HLT:
                case KVM_CAP_MMU_SHADOW_CACHE_CONTROL:
+               case KVM_CAP_USER_MEMORY:
                        r = 1;
                        break;
                default:
 
        __u64 memory_size; /* bytes */
 };
 
+/* for KVM_SET_USER_MEMORY_REGION */
+struct kvm_userspace_memory_region {
+       __u32 slot;
+       __u32 flags;
+       __u64 guest_phys_addr;
+       __u64 memory_size; /* bytes */
+       __u64 userspace_addr; /* start of the userspace allocated memory */
+};
+
 /* for kvm_memory_region::flags */
 #define KVM_MEM_LOG_DIRTY_PAGES  1UL
 
 #define KVM_CAP_IRQCHIP          0
 #define KVM_CAP_HLT      1
 #define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2
+#define KVM_CAP_USER_MEMORY 3
 
 /*
  * ioctls for VM fds
 #define KVM_SET_MEMORY_REGION     _IOW(KVMIO, 0x40, struct kvm_memory_region)
 #define KVM_SET_NR_MMU_PAGES      _IO(KVMIO, 0x44)
 #define KVM_GET_NR_MMU_PAGES      _IO(KVMIO, 0x45)
+#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46,\
+                                       struct kvm_userspace_memory_region)
 /*
  * KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
  * a vcpu fd.