@@ -49,9 +49,169 @@ struct ne_cpu_pool {
static struct ne_cpu_pool ne_cpu_pool;
+static long ne_enclave_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+static int ne_enclave_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static __poll_t ne_enclave_poll(struct file *file, poll_table *wait)
+{
+ __poll_t mask = 0;
+ struct ne_enclave *ne_enclave = file->private_data;
+
+ poll_wait(file, &ne_enclave->eventq, wait);
+
+ if (!ne_enclave->has_event)
+ return mask;
+
+ mask = POLLHUP;
+
+ return mask;
+}
+
+static const struct file_operations ne_enclave_fops = {
+ .owner = THIS_MODULE,
+ .llseek = noop_llseek,
+ .poll = ne_enclave_poll,
+ .unlocked_ioctl = ne_enclave_ioctl,
+ .release = ne_enclave_release,
+};
+
+/**
+ * ne_create_vm_ioctl - Alloc slot to be associated with an enclave. Create
+ * enclave file descriptor to be further used for enclave resources handling
+ * e.g. memory regions and CPUs.
+ *
+ * This function gets called with the ne_pci_dev enclave mutex held.
+ *
+ * @pdev: PCI device used for enclave lifetime management.
+ * @ne_pci_dev: private data associated with the PCI device.
+ * @type: type of the virtual machine to be created.
+ *
+ * @returns: enclave fd on success, negative return value on failure.
+ */
+static int ne_create_vm_ioctl(struct pci_dev *pdev,
+ struct ne_pci_dev *ne_pci_dev, unsigned long type)
+{
+ struct ne_pci_dev_cmd_reply cmd_reply = {};
+ int fd = 0;
+ struct file *file = NULL;
+ struct ne_enclave *ne_enclave = NULL;
+ int rc = -EINVAL;
+ struct slot_alloc_req slot_alloc_req = {};
+
+ ne_enclave = kzalloc(sizeof(*ne_enclave), GFP_KERNEL);
+ if (!ne_enclave)
+ return -ENOMEM;
+
+ if (!zalloc_cpumask_var(&ne_enclave->cpu_siblings, GFP_KERNEL)) {
+ kfree(ne_enclave);
+
+ return -ENOMEM;
+ }
+
+ fd = get_unused_fd_flags(O_CLOEXEC);
+ if (fd < 0) {
+ rc = fd;
+
+ pr_err_ratelimited(NE "Error in getting unused fd [rc=%d]\n",
+ rc);
+
+ goto free_cpumask;
+ }
+
+ file = anon_inode_getfile("ne-vm", &ne_enclave_fops, ne_enclave,
+ O_RDWR);
+ if (IS_ERR(file)) {
+ rc = PTR_ERR(file);
+
+ pr_err_ratelimited(NE "Error in anon inode get file [rc=%d]\n",
+ rc);
+
+ goto put_fd;
+ }
+
+ ne_enclave->pdev = pdev;
+
+ rc = ne_do_request(ne_enclave->pdev, SLOT_ALLOC, &slot_alloc_req,
+ sizeof(slot_alloc_req), &cmd_reply,
+ sizeof(cmd_reply));
+ if (rc < 0) {
+ pr_err_ratelimited(NE "Error in slot alloc [rc=%d]\n", rc);
+
+ goto put_file;
+ }
+
+ init_waitqueue_head(&ne_enclave->eventq);
+ ne_enclave->has_event = false;
+ mutex_init(&ne_enclave->enclave_info_mutex);
+ ne_enclave->max_mem_regions = cmd_reply.mem_regions;
+ INIT_LIST_HEAD(&ne_enclave->mem_regions_list);
+ ne_enclave->mm = current->mm;
+ ne_enclave->slot_uid = cmd_reply.slot_uid;
+ ne_enclave->state = NE_STATE_INIT;
+ INIT_LIST_HEAD(&ne_enclave->vcpu_ids_list);
+
+ list_add(&ne_enclave->enclave_list_entry, &ne_pci_dev->enclaves_list);
+
+ fd_install(fd, file);
+
+ return fd;
+
+put_file:
+ fput(file);
+put_fd:
+ put_unused_fd(fd);
+free_cpumask:
+ free_cpumask_var(ne_enclave->cpu_siblings);
+ kfree(ne_enclave);
+
+ return rc;
+}
+
static long ne_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
+ struct ne_pci_dev *ne_pci_dev = NULL;
+ struct pci_dev *pdev = pci_get_device(PCI_VENDOR_ID_AMAZON,
+ PCI_DEVICE_ID_NE, NULL);
+
+ if (!pdev)
+ return -EINVAL;
+
+ ne_pci_dev = pci_get_drvdata(pdev);
+ if (!ne_pci_dev)
+ return -EINVAL;
+
switch (cmd) {
+ case KVM_CREATE_VM: {
+ int rc = -EINVAL;
+ unsigned long type = 0;
+
+ if (copy_from_user(&type, (void *)arg, sizeof(type))) {
+ pr_err_ratelimited(NE "Error in copy from user\n");
+
+ return -EFAULT;
+ }
+
+ mutex_lock(&ne_pci_dev->enclaves_list_mutex);
+
+ rc = ne_create_vm_ioctl(pdev, ne_pci_dev, type);
+
+ mutex_unlock(&ne_pci_dev->enclaves_list_mutex);
+
+ return rc;
+ }
default:
return -ENOTTY;