lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <7a08c41e1825095814f8c35854d3938c084b2368.1692892275.git.reinette.chatre@intel.com>
Date:   Thu, 24 Aug 2023 09:15:21 -0700
From:   Reinette Chatre <reinette.chatre@...el.com>
To:     jgg@...dia.com, yishaih@...dia.com,
        shameerali.kolothum.thodi@...wei.com, kevin.tian@...el.com,
        alex.williamson@...hat.com
Cc:     kvm@...r.kernel.org, dave.jiang@...el.com, jing2.liu@...el.com,
        ashok.raj@...el.com, fenghua.yu@...el.com,
        tom.zanussi@...ux.intel.com, reinette.chatre@...el.com,
        linux-kernel@...r.kernel.org
Subject: [RFC PATCH 2/3] vfio/ims: Support emulated interrupts

Access from a guest to a virtual device may be either 'direct-path',
where the guest interacts directly with the underlying hardware,
or 'intercepted path' where the virtual device emulates operations.

Support emulated interrupts that can be used to handle 'intercepted
path' operations. For example, a virtual device may use 'intercepted
path' for configuration. Doing so, configuration requests intercepted
by the virtual device driver are handled within the virtual device
driver with completion signaled to the guest without interacting with
the underlying hardware.

Add vfio_pci_ims_set_emulated() and vfio_pci_ims_send_signal() to
the VFIO PCI IMS API. vfio_pci_ims_set_emulated() configures a
range of interrupts that are emulated. Any range of interrupts
can be configured as emulated as long as no IMS interrupt has
previously been allocated at that vector. The virtual device
uses vfio_pci_ims_send_signal() to trigger interrupts in the guest.

Originally-by: Dave Jiang <dave.jiang@...el.com>
Signed-off-by: Reinette Chatre <reinette.chatre@...el.com>
---
 drivers/vfio/pci/vfio_pci_ims.c | 117 ++++++++++++++++++++++++++++----
 include/linux/vfio.h            |  14 ++++
 2 files changed, 117 insertions(+), 14 deletions(-)

diff --git a/drivers/vfio/pci/vfio_pci_ims.c b/drivers/vfio/pci/vfio_pci_ims.c
index 0926eb921351..fe5b3484ad34 100644
--- a/drivers/vfio/pci/vfio_pci_ims.c
+++ b/drivers/vfio/pci/vfio_pci_ims.c
@@ -17,16 +17,18 @@
 #include <linux/xarray.h>
 
 /*
- * IMS interrupt context.
- * @name:	Name of device associated with interrupt.
+ * Interrupt context. Used for emulated as well as IMS interrupts.
+ * @emulated:	(IMS and emulated) true if context belongs to emulated interrupt.
+ * @name:	(IMS and emulated) Name of device associated with interrupt.
  *		Provided to request_irq().
- * @trigger:	eventfd associated with interrupt.
- * @producer:	Interrupt's registered IRQ bypass producer.
- * @ims_id:	Interrupt index associated with IMS interrupt.
- * @virq:	Linux IRQ number associated with IMS interrupt.
- * @icookie:	Cookie used by irqchip driver.
+ * @trigger:	(IMS and emulated) eventfd associated with interrupt.
+ * @producer:	(IMS only) Interrupt's registered IRQ bypass producer.
+ * @ims_id:	(IMS only) Interrupt index associated with IMS interrupt.
+ * @virq:	(IMS only) Linux IRQ number associated with IMS interrupt.
+ * @icookie:	(IMS only) Cookie used by irqchip driver.
  */
 struct vfio_pci_ims_ctx {
+	bool				emulated;
 	char				*name;
 	struct eventfd_ctx		*trigger;
 	struct irq_bypass_producer	producer;
@@ -35,6 +37,31 @@ struct vfio_pci_ims_ctx {
 	union msi_instance_cookie	icookie;
 };
 
+/*
+ * Send signal to the eventfd.
+ * @vdev:	VFIO device
+ * @vector:	MSI-X vector of @vdev for which interrupt will be signaled
+ *
+ * Intended for use to send signal for emulated interrupts.
+ */
+void vfio_pci_ims_send_signal(struct vfio_device *vdev, unsigned int vector)
+{
+	struct vfio_pci_ims *ims = &vdev->ims;
+	struct vfio_pci_ims_ctx *ctx;
+
+	mutex_lock(&ims->ctx_mutex);
+	ctx = xa_load(&ims->ctx, vector);
+
+	if (WARN_ON_ONCE(!ctx || !ctx->emulated || !ctx->trigger)) {
+		mutex_unlock(&ims->ctx_mutex);
+		return;
+	}
+
+	eventfd_signal(ctx->trigger, 1);
+	mutex_unlock(&ims->ctx_mutex);
+}
+EXPORT_SYMBOL_GPL(vfio_pci_ims_send_signal);
+
 static irqreturn_t vfio_pci_ims_irq_handler(int irq, void *arg)
 {
 	struct eventfd_ctx *trigger = arg;
@@ -46,7 +73,8 @@ static irqreturn_t vfio_pci_ims_irq_handler(int irq, void *arg)
 /*
  * Free the interrupt associated with @ctx.
  *
- * Free interrupt from the underlying PCI device's IMS domain.
+ * For an emulated interrupt there is nothing to do. For an IMS interrupt
+ * the interrupt is freed from the underlying PCI device's IMS domain.
  */
 static void vfio_pci_ims_irq_free(struct vfio_pci_ims *ims,
 				  struct vfio_pci_ims_ctx *ctx)
@@ -55,6 +83,9 @@ static void vfio_pci_ims_irq_free(struct vfio_pci_ims *ims,
 
 	lockdep_assert_held(&ims->ctx_mutex);
 
+	if (ctx->emulated)
+		return;
+
 	irq_map.index = ctx->ims_id;
 	irq_map.virq = ctx->virq;
 	pci_ims_free_irq(ims->pdev, irq_map);
@@ -65,7 +96,8 @@ static void vfio_pci_ims_irq_free(struct vfio_pci_ims *ims,
 /*
  * Allocate an interrupt for @ctx.
  *
- * Allocate interrupt from the underlying PCI device's IMS domain.
+ * For an emulated interrupt there is nothing to do. For an IMS interrupt
+ * the interrupt is allocated from the underlying PCI device's IMS domain.
  */
 static int vfio_pci_ims_irq_alloc(struct vfio_pci_ims *ims,
 				  struct vfio_pci_ims_ctx *ctx)
@@ -74,6 +106,9 @@ static int vfio_pci_ims_irq_alloc(struct vfio_pci_ims *ims,
 
 	lockdep_assert_held(&ims->ctx_mutex);
 
+	if (ctx->emulated)
+		return -EINVAL;
+
 	irq_map = pci_ims_alloc_irq(ims->pdev, &ctx->icookie, NULL);
 	if (irq_map.index < 0)
 		return irq_map.index;
@@ -133,9 +168,11 @@ static int vfio_pci_ims_set_vector_signal(struct vfio_device *vdev,
 	ctx = xa_load(&ims->ctx, vector);
 
 	if (ctx && ctx->trigger) {
-		irq_bypass_unregister_producer(&ctx->producer);
-		free_irq(ctx->virq, ctx->trigger);
-		vfio_pci_ims_irq_free(ims, ctx);
+		if (!ctx->emulated) {
+			irq_bypass_unregister_producer(&ctx->producer);
+			free_irq(ctx->virq, ctx->trigger);
+			vfio_pci_ims_irq_free(ims, ctx);
+		}
 		kfree(ctx->name);
 		ctx->name = NULL;
 		eventfd_ctx_put(ctx->trigger);
@@ -163,6 +200,9 @@ static int vfio_pci_ims_set_vector_signal(struct vfio_device *vdev,
 
 	ctx->trigger = trigger;
 
+	if (ctx->emulated)
+		return 0;
+
 	ret = vfio_pci_ims_irq_alloc(ims, ctx);
 	if (ret < 0)
 		goto out_put_eventfd_ctx;
@@ -219,8 +259,8 @@ static int vfio_pci_ims_set_block(struct vfio_device *vdev, unsigned int start,
 }
 
 /*
- * Manage Interrupt Message Store (IMS) interrupts on the host that are
- * backing guest MSI-X vectors.
+ * Manage Interrupt Message Store (IMS) or emulated interrupts on the
+ * host that are backing guest MSI-X vectors.
  *
  * @vdev:	 VFIO device
  * @index:	 Type of guest vectors to set up.  Must be
@@ -360,6 +400,10 @@ int vfio_pci_ims_set_cookie(struct vfio_device *vdev, unsigned int vector,
 	mutex_lock(&ims->ctx_mutex);
 	ctx = xa_load(&ims->ctx, vector);
 	if (ctx) {
+		if (WARN_ON_ONCE(ctx->emulated)) {
+			ret = -EINVAL;
+			goto out_unlock;
+		}
 		ctx->icookie = *icookie;
 		goto out_unlock;
 	}
@@ -385,5 +429,50 @@ int vfio_pci_ims_set_cookie(struct vfio_device *vdev, unsigned int vector,
 }
 EXPORT_SYMBOL_GPL(vfio_pci_ims_set_cookie);
 
+/*
+ * Set range of interrupts that will be emulated instead of backed by IMS.
+ *
+ * Return: error code on failure (-EBUSY if the vector is not available,
+ * -ENOMEM on allocation failure), 0 on success
+ */
+int vfio_pci_ims_set_emulated(struct vfio_device *vdev, unsigned int start,
+			      unsigned int count)
+{
+	struct vfio_pci_ims *ims = &vdev->ims;
+	struct vfio_pci_ims_ctx *ctx;
+	unsigned long i, j;
+	int ret = 0;
+
+	mutex_lock(&ims->ctx_mutex);
+
+	for (i = start; i < start + count; i++) {
+		ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
+		if (!ctx) {
+			ret = -ENOMEM;
+			goto out_err;
+		}
+		ctx->emulated = true;
+		ret = xa_insert(&ims->ctx, i, ctx, GFP_KERNEL_ACCOUNT);
+		if (ret) {
+			kfree(ctx);
+			goto out_err;
+		}
+	}
+
+	mutex_unlock(&ims->ctx_mutex);
+	return 0;
+
+out_err:
+	for (j = start; j < i; j++) {
+		ctx = xa_load(&ims->ctx, j);
+		xa_erase(&ims->ctx, j);
+		kfree(ctx);
+	}
+	mutex_unlock(&ims->ctx_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(vfio_pci_ims_set_emulated);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Intel Corporation");
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index aa54239bff4d..906220002ff4 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -334,6 +334,9 @@ int vfio_pci_set_ims_trigger(struct vfio_device *vdev, unsigned int index,
 void vfio_pci_ims_init(struct vfio_device *vdev, struct pci_dev *pdev,
 		       union msi_instance_cookie *default_cookie);
 void vfio_pci_ims_free(struct vfio_device *vdev);
+int vfio_pci_ims_set_emulated(struct vfio_device *vdev, unsigned int start,
+			      unsigned int count);
+void vfio_pci_ims_send_signal(struct vfio_device *vdev, unsigned int vector);
 int vfio_pci_ims_set_cookie(struct vfio_device *vdev, unsigned int vector,
 			    union msi_instance_cookie *icookie);
 #else
@@ -353,6 +356,17 @@ static inline void vfio_pci_ims_init(struct vfio_device *vdev,
 
 static inline void vfio_pci_ims_free(struct vfio_device *vdev) {}
 
+static inline int vfio_pci_ims_set_emulated(struct vfio_device *vdev,
+					    unsigned int start,
+					    unsigned int count)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline void vfio_pci_ims_send_signal(struct vfio_device *vdev,
+					    unsigned int vector)
+{}
+
 static inline int vfio_pci_ims_set_cookie(struct vfio_device *vdev,
 					  unsigned int vector,
 					  union msi_instance_cookie *icookie)
-- 
2.34.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ