return rc;
 }
 
+/**
+ * ne_start_enclave_ioctl() - Trigger enclave start after the enclave resources,
+ *                           such as memory and CPU, have been set.
+ * @ne_enclave :               Private data associated with the current enclave.
+ * @enclave_start_info :       Enclave info that includes enclave cid and flags.
+ *
+ * Context: Process context. This function is called with the ne_enclave mutex held.
+ * Return:
+ * * 0 on success.
+ * * Negative return value on failure.
+ */
+static int ne_start_enclave_ioctl(struct ne_enclave *ne_enclave,
+       struct ne_enclave_start_info *enclave_start_info)
+{
+       struct ne_pci_dev_cmd_reply cmd_reply = {};
+       unsigned int cpu = 0;
+       struct enclave_start_req enclave_start_req = {};
+       unsigned int i = 0;
+       struct pci_dev *pdev = ne_devs.ne_pci_dev->pdev;
+       int rc = -EINVAL;
+
+       if (!ne_enclave->nr_mem_regions) {
+               dev_err_ratelimited(ne_misc_dev.this_device,
+                                   "Enclave has no mem regions\n");
+
+               return -NE_ERR_NO_MEM_REGIONS_ADDED;
+       }
+
+       if (ne_enclave->mem_size < NE_MIN_ENCLAVE_MEM_SIZE) {
+               dev_err_ratelimited(ne_misc_dev.this_device,
+                                   "Enclave memory is less than %ld\n",
+                                   NE_MIN_ENCLAVE_MEM_SIZE);
+
+               return -NE_ERR_ENCLAVE_MEM_MIN_SIZE;
+       }
+
+       if (!ne_enclave->nr_vcpus) {
+               dev_err_ratelimited(ne_misc_dev.this_device,
+                                   "Enclave has no vCPUs\n");
+
+               return -NE_ERR_NO_VCPUS_ADDED;
+       }
+
+       for (i = 0; i < ne_enclave->nr_parent_vm_cores; i++)
+               for_each_cpu(cpu, ne_enclave->threads_per_core[i])
+                       if (!cpumask_test_cpu(cpu, ne_enclave->vcpu_ids)) {
+                               dev_err_ratelimited(ne_misc_dev.this_device,
+                                                   "Full CPU cores not used\n");
+
+                               return -NE_ERR_FULL_CORES_NOT_USED;
+                       }
+
+       enclave_start_req.enclave_cid = enclave_start_info->enclave_cid;
+       enclave_start_req.flags = enclave_start_info->flags;
+       enclave_start_req.slot_uid = ne_enclave->slot_uid;
+
+       rc = ne_do_request(pdev, ENCLAVE_START,
+                          &enclave_start_req, sizeof(enclave_start_req),
+                          &cmd_reply, sizeof(cmd_reply));
+       if (rc < 0) {
+               dev_err_ratelimited(ne_misc_dev.this_device,
+                                   "Error in enclave start [rc=%d]\n", rc);
+
+               return rc;
+       }
+
+       ne_enclave->state = NE_STATE_RUNNING;
+
+       enclave_start_info->enclave_cid = cmd_reply.enclave_cid;
+
+       return 0;
+}
+
 /**
  * ne_enclave_ioctl() - Ioctl function provided by the enclave file.
  * @file:      File associated with this ioctl function.
                return 0;
        }
 
+       case NE_START_ENCLAVE: {
+               struct ne_enclave_start_info enclave_start_info = {};
+               int rc = -EINVAL;
+
+               if (copy_from_user(&enclave_start_info, (void __user *)arg,
+                                  sizeof(enclave_start_info)))
+                       return -EFAULT;
+
+               if (enclave_start_info.flags >= NE_ENCLAVE_START_MAX_FLAG_VAL) {
+                       dev_err_ratelimited(ne_misc_dev.this_device,
+                                           "Incorrect flag in enclave start info\n");
+
+                       return -NE_ERR_INVALID_FLAG_VALUE;
+               }
+
+               /*
+                * Do not use well-known CIDs - 0, 1, 2 - for enclaves.
+                * VMADDR_CID_ANY = -1U
+                * VMADDR_CID_HYPERVISOR = 0
+                * VMADDR_CID_LOCAL = 1
+                * VMADDR_CID_HOST = 2
+                * Note: 0 is used as a placeholder to auto-generate an enclave CID.
+                * http://man7.org/linux/man-pages/man7/vsock.7.html
+                */
+               if (enclave_start_info.enclave_cid > 0 &&
+                   enclave_start_info.enclave_cid <= VMADDR_CID_HOST) {
+                       dev_err_ratelimited(ne_misc_dev.this_device,
+                                           "Well-known CID value, not to be used for enclaves\n");
+
+                       return -NE_ERR_INVALID_ENCLAVE_CID;
+               }
+
+               if (enclave_start_info.enclave_cid == U32_MAX) {
+                       dev_err_ratelimited(ne_misc_dev.this_device,
+                                           "Well-known CID value, not to be used for enclaves\n");
+
+                       return -NE_ERR_INVALID_ENCLAVE_CID;
+               }
+
+               /*
+                * Do not use the CID of the primary / parent VM for enclaves.
+                */
+               if (enclave_start_info.enclave_cid == NE_PARENT_VM_CID) {
+                       dev_err_ratelimited(ne_misc_dev.this_device,
+                                           "CID of the parent VM, not to be used for enclaves\n");
+
+                       return -NE_ERR_INVALID_ENCLAVE_CID;
+               }
+
+               /* 64-bit CIDs are not yet supported for the vsock device. */
+               if (enclave_start_info.enclave_cid > U32_MAX) {
+                       dev_err_ratelimited(ne_misc_dev.this_device,
+                                           "64-bit CIDs not yet supported for the vsock device\n");
+
+                       return -NE_ERR_INVALID_ENCLAVE_CID;
+               }
+
+               mutex_lock(&ne_enclave->enclave_info_mutex);
+
+               if (ne_enclave->state != NE_STATE_INIT) {
+                       dev_err_ratelimited(ne_misc_dev.this_device,
+                                           "Enclave is not in init state\n");
+
+                       mutex_unlock(&ne_enclave->enclave_info_mutex);
+
+                       return -NE_ERR_NOT_IN_INIT_STATE;
+               }
+
+               rc = ne_start_enclave_ioctl(ne_enclave, &enclave_start_info);
+               if (rc < 0) {
+                       mutex_unlock(&ne_enclave->enclave_info_mutex);
+
+                       return rc;
+               }
+
+               mutex_unlock(&ne_enclave->enclave_info_mutex);
+
+               if (copy_to_user((void __user *)arg, &enclave_start_info,
+                                sizeof(enclave_start_info)))
+                       return -EFAULT;
+
+               return 0;
+       }
+
        default:
                return -ENOTTY;
        }