/** * NE_DEFAULT_TIMEOUT_MSECS - Default timeout to wait for a reply from * the NE PCI device.
*/ #define NE_DEFAULT_TIMEOUT_MSECS (120000) /* 120 sec */
/** * ne_submit_request() - Submit command request to the PCI device based on the * command type. * @pdev: PCI device to send the command to. * @cmd_type: Command type of the request sent to the PCI device. * @cmd_request: Command request payload. * @cmd_request_size: Size of the command request payload. * * Context: Process context. This function is called with the ne_pci_dev mutex held.
*/ staticvoid ne_submit_request(struct pci_dev *pdev, enum ne_pci_dev_cmd_type cmd_type, void *cmd_request, size_t cmd_request_size)
{ struct ne_pci_dev *ne_pci_dev = pci_get_drvdata(pdev);
/** * ne_retrieve_reply() - Retrieve reply from the PCI device. * @pdev: PCI device to receive the reply from. * @cmd_reply: Command reply payload. * @cmd_reply_size: Size of the command reply payload. * * Context: Process context. This function is called with the ne_pci_dev mutex held.
*/ staticvoid ne_retrieve_reply(struct pci_dev *pdev, struct ne_pci_dev_cmd_reply *cmd_reply,
size_t cmd_reply_size)
{ struct ne_pci_dev *ne_pci_dev = pci_get_drvdata(pdev);
/** * ne_wait_for_reply() - Wait for a reply of a PCI device command. * @pdev: PCI device for which a reply is waited. * * Context: Process context. This function is called with the ne_pci_dev mutex held. * Return: * * 0 on success. * * Negative return value on failure.
*/ staticint ne_wait_for_reply(struct pci_dev *pdev)
{ struct ne_pci_dev *ne_pci_dev = pci_get_drvdata(pdev); int rc = -EINVAL;
/* * TODO: Update to _interruptible and handle interrupted wait event * e.g. -ERESTARTSYS, incoming signals + update timeout, if needed.
*/
rc = wait_event_timeout(ne_pci_dev->cmd_reply_wait_q,
atomic_read(&ne_pci_dev->cmd_reply_avail) != 0,
msecs_to_jiffies(NE_DEFAULT_TIMEOUT_MSECS)); if (!rc) return -ETIMEDOUT;
/** * ne_reply_handler() - Interrupt handler for retrieving a reply matching a * request sent to the PCI device for enclave lifetime * management. * @irq: Received interrupt for a reply sent by the PCI device. * @args: PCI device private data structure. * * Context: Interrupt context. * Return: * * IRQ_HANDLED on handled interrupt.
*/ static irqreturn_t ne_reply_handler(int irq, void *args)
{ struct ne_pci_dev *ne_pci_dev = (struct ne_pci_dev *)args;
atomic_set(&ne_pci_dev->cmd_reply_avail, 1);
/* TODO: Update to _interruptible. */
wake_up(&ne_pci_dev->cmd_reply_wait_q);
return IRQ_HANDLED;
}
/** * ne_event_work_handler() - Work queue handler for notifying enclaves on a * state change received by the event interrupt * handler. * @work: Item containing the NE PCI device for which an out-of-band event * was issued. * * An out-of-band event is being issued by the Nitro Hypervisor when at least * one enclave is changing state without client interaction. * * Context: Work queue context.
*/ staticvoid ne_event_work_handler(struct work_struct *work)
{ struct ne_pci_dev_cmd_reply cmd_reply = {}; struct ne_enclave *ne_enclave = NULL; struct ne_pci_dev *ne_pci_dev =
container_of(work, struct ne_pci_dev, notify_work); struct pci_dev *pdev = ne_pci_dev->pdev; int rc = -EINVAL; struct slot_info_req slot_info_req = {};
mutex_lock(&ne_pci_dev->enclaves_list_mutex);
/* * Iterate over all enclaves registered for the Nitro Enclaves * PCI device and determine for which enclave(s) the out-of-band event * is corresponding to.
*/
list_for_each_entry(ne_enclave, &ne_pci_dev->enclaves_list, enclave_list_entry) {
mutex_lock(&ne_enclave->enclave_info_mutex);
/* * Enclaves that were never started cannot receive out-of-band * events.
*/ if (ne_enclave->state != NE_STATE_RUNNING) goto unlock;
slot_info_req.slot_uid = ne_enclave->slot_uid;
rc = ne_do_request(pdev, SLOT_INFO,
&slot_info_req, sizeof(slot_info_req),
&cmd_reply, sizeof(cmd_reply)); if (rc < 0)
dev_err(&pdev->dev, "Error in slot info [rc=%d]\n", rc);
/* Notify enclave process that the enclave state changed. */ if (ne_enclave->state != cmd_reply.state) {
ne_enclave->state = cmd_reply.state;
/** * ne_event_handler() - Interrupt handler for PCI device out-of-band events. * This interrupt does not supply any data in the MMIO * region. It notifies a change in the state of any of * the launched enclaves. * @irq: Received interrupt for an out-of-band event. * @args: PCI device private data structure. * * Context: Interrupt context. * Return: * * IRQ_HANDLED on handled interrupt.
*/ static irqreturn_t ne_event_handler(int irq, void *args)
{ struct ne_pci_dev *ne_pci_dev = (struct ne_pci_dev *)args;
dev_err(&pdev->dev, "Error in getting vec count [rc=%d]\n", rc);
return rc;
}
rc = pci_alloc_irq_vectors(pdev, nr_vecs, nr_vecs, PCI_IRQ_MSIX); if (rc < 0) {
dev_err(&pdev->dev, "Error in alloc MSI-X vecs [rc=%d]\n", rc);
return rc;
}
/* * This IRQ gets triggered every time the PCI device responds to a * command request. The reply is then retrieved, reading from the MMIO * space of the PCI device.
*/
rc = request_irq(pci_irq_vector(pdev, NE_VEC_REPLY), ne_reply_handler,
0, "enclave_cmd", ne_pci_dev); if (rc < 0) {
dev_err(&pdev->dev, "Error in request irq reply [rc=%d]\n", rc);
goto free_irq_vectors;
}
ne_pci_dev->event_wq = create_singlethread_workqueue("ne_pci_dev_wq"); if (!ne_pci_dev->event_wq) {
rc = -ENOMEM;
dev_err(&pdev->dev, "Cannot get wq for dev events [rc=%d]\n", rc);
/* * This IRQ gets triggered every time any enclave's state changes. Its * handler then scans for the changes and propagates them to the user * space.
*/
rc = request_irq(pci_irq_vector(pdev, NE_VEC_EVENT), ne_event_handler,
0, "enclave_evt", ne_pci_dev); if (rc < 0) {
dev_err(&pdev->dev, "Error in request irq event [rc=%d]\n", rc);
/** * ne_pci_dev_enable() - Select the PCI device version and enable it. * @pdev: PCI device to select version for and then enable. * * Context: Process context. * Return: * * 0 on success. * * Negative return value on failure.
*/ staticint ne_pci_dev_enable(struct pci_dev *pdev)
{
u8 dev_enable_reply = 0;
u16 dev_version_reply = 0; struct ne_pci_dev *ne_pci_dev = pci_get_drvdata(pdev);
dev_version_reply = ioread16(ne_pci_dev->iomem_base + NE_VERSION); if (dev_version_reply != NE_VERSION_MAX) {
dev_err(&pdev->dev, "Error in pci dev version cmd\n");
/* * Check for NE_ENABLE_OFF in a loop, to handle cases when the device * state is not immediately set to disabled and going through a * transitory state of disabling.
*/ while (sleep_time_count < NE_DEFAULT_TIMEOUT_MSECS) {
dev_disable_reply = ioread8(ne_pci_dev->iomem_base + NE_ENABLE); if (dev_disable_reply == NE_ENABLE_OFF) return;
dev_disable_reply = ioread8(ne_pci_dev->iomem_base + NE_ENABLE); if (dev_disable_reply != NE_ENABLE_OFF)
dev_err(&pdev->dev, "Error in pci dev disable cmd\n");
}
/** * ne_pci_probe() - Probe function for the NE PCI device. * @pdev: PCI device to match with the NE PCI driver. * @id : PCI device id table associated with the NE PCI driver. * * Context: Process context. * Return: * * 0 on success. * * Negative return value on failure.
*/ staticint ne_pci_probe(struct pci_dev *pdev, conststruct pci_device_id *id)
{ struct ne_pci_dev *ne_pci_dev = NULL; int rc = -EINVAL;
ne_pci_dev = kzalloc(sizeof(*ne_pci_dev), GFP_KERNEL); if (!ne_pci_dev) return -ENOMEM;
rc = pci_enable_device(pdev); if (rc < 0) {
dev_err(&pdev->dev, "Error in pci dev enable [rc=%d]\n", rc);
goto free_ne_pci_dev;
}
pci_set_master(pdev);
rc = pci_request_regions_exclusive(pdev, "nitro_enclaves"); if (rc < 0) {
dev_err(&pdev->dev, "Error in pci request regions [rc=%d]\n", rc);
/** * ne_pci_remove() - Remove function for the NE PCI device. * @pdev: PCI device associated with the NE PCI driver. * * Context: Process context.
*/ staticvoid ne_pci_remove(struct pci_dev *pdev)
{ struct ne_pci_dev *ne_pci_dev = pci_get_drvdata(pdev);
misc_deregister(ne_devs.ne_misc_dev);
ne_devs.ne_pci_dev = NULL;
ne_pci_dev_disable(pdev);
ne_teardown_msix(pdev);
pci_set_drvdata(pdev, NULL);
pci_iounmap(pdev, ne_pci_dev->iomem_base);
pci_release_regions(pdev);
pci_disable_device(pdev);
kfree(ne_pci_dev);
}
/** * ne_pci_shutdown() - Shutdown function for the NE PCI device. * @pdev: PCI device associated with the NE PCI driver. * * Context: Process context.
*/ staticvoid ne_pci_shutdown(struct pci_dev *pdev)
{ struct ne_pci_dev *ne_pci_dev = pci_get_drvdata(pdev);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.