#define KVM_CAP_MEMORY_ATTRIBUTES 233
 #define KVM_CAP_GUEST_MEMFD 234
 #define KVM_CAP_VM_TYPES 235
+#define KVM_CAP_PRE_FAULT_MEMORY 236
 
 struct kvm_irq_routing_irqchip {
        __u32 irqchip;
        __u64 reserved[6];
 };
 
+#define KVM_PRE_FAULT_MEMORY   _IOWR(KVMIO, 0xd5, struct kvm_pre_fault_memory)
+
+struct kvm_pre_fault_memory {
+       __u64 gpa;
+       __u64 size;
+       __u64 flags;
+       __u64 padding[5];
+};
+
 #endif /* __LINUX_KVM_H */
 
        return fd;
 }
 
+#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY
+static int kvm_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu,
+                                    struct kvm_pre_fault_memory *range)
+{
+       int idx;
+       long r;
+       u64 full_size;
+
+       if (range->flags)
+               return -EINVAL;
+
+       if (!PAGE_ALIGNED(range->gpa) ||
+           !PAGE_ALIGNED(range->size) ||
+           range->gpa + range->size <= range->gpa)
+               return -EINVAL;
+
+       vcpu_load(vcpu);
+       idx = srcu_read_lock(&vcpu->kvm->srcu);
+
+       full_size = range->size;
+       do {
+               if (signal_pending(current)) {
+                       r = -EINTR;
+                       break;
+               }
+
+               r = kvm_arch_vcpu_pre_fault_memory(vcpu, range);
+               if (WARN_ON_ONCE(r == 0 || r == -EIO))
+                       break;
+
+               if (r < 0)
+                       break;
+
+               range->size -= r;
+               range->gpa += r;
+               cond_resched();
+       } while (range->size);
+
+       srcu_read_unlock(&vcpu->kvm->srcu, idx);
+       vcpu_put(vcpu);
+
+       /* Return success if at least one page was mapped successfully.  */
+       return full_size == range->size ? r : 0;
+}
+#endif
+
 static long kvm_vcpu_ioctl(struct file *filp,
                           unsigned int ioctl, unsigned long arg)
 {
                r = kvm_vcpu_ioctl_get_stats_fd(vcpu);
                break;
        }
+#ifdef CONFIG_KVM_GENERIC_PRE_FAULT_MEMORY
+       case KVM_PRE_FAULT_MEMORY: {
+               struct kvm_pre_fault_memory range;
+
+               r = -EFAULT;
+               if (copy_from_user(&range, argp, sizeof(range)))
+                       break;
+               r = kvm_vcpu_pre_fault_memory(vcpu, &range);
+               /* Pass back leftover range. */
+               if (copy_to_user(argp, &range, sizeof(range)))
+                       r = -EFAULT;
+               break;
+       }
+#endif
        default:
                r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
        }