summaryrefslogtreecommitdiffstats
path: root/system/xen/xsa/xsa237-4.9-0004-x86-IRQ-conditionally-preserve-irq-pirq-mapping-on-error.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/xen/xsa/xsa237-4.9-0004-x86-IRQ-conditionally-preserve-irq-pirq-mapping-on-error.patch')
-rw-r--r--system/xen/xsa/xsa237-4.9-0004-x86-IRQ-conditionally-preserve-irq-pirq-mapping-on-error.patch124
1 files changed, 124 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa237-4.9-0004-x86-IRQ-conditionally-preserve-irq-pirq-mapping-on-error.patch b/system/xen/xsa/xsa237-4.9-0004-x86-IRQ-conditionally-preserve-irq-pirq-mapping-on-error.patch
new file mode 100644
index 0000000000..a16ec1bba1
--- /dev/null
+++ b/system/xen/xsa/xsa237-4.9-0004-x86-IRQ-conditionally-preserve-irq-pirq-mapping-on-error.patch
@@ -0,0 +1,124 @@
+From: Jan Beulich <jbeulich@suse.com>
+Subject: x86/IRQ: conditionally preserve irq <-> pirq mapping on map error paths
+
+Mappings that had been set up before should not be torn down when
+handling unrelated errors.
+
+This is part of XSA-237.
+
+Reported-by: HW42 <hw42@ipsumj.de>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Reviewed-by: George Dunlap <george.dunlap@citrix.com>
+
+--- a/xen/arch/x86/irq.c
++++ b/xen/arch/x86/irq.c
+@@ -1251,7 +1251,8 @@ static int prepare_domain_irq_pirq(struc
+ return -ENOMEM;
+ }
+ *pinfo = info;
+- return 0;
++
++ return !!err;
+ }
+
+ static void set_domain_irq_pirq(struct domain *d, int irq, struct pirq *pirq)
+@@ -1294,7 +1295,10 @@ int init_domain_irq_mapping(struct domai
+ continue;
+ err = prepare_domain_irq_pirq(d, i, i, &info);
+ if ( err )
++ {
++ ASSERT(err < 0);
+ break;
++ }
+ set_domain_irq_pirq(d, i, info);
+ }
+
+@@ -1902,6 +1906,7 @@ int map_domain_pirq(
+ struct pirq *info;
+ struct irq_desc *desc;
+ unsigned long flags;
++ DECLARE_BITMAP(prepared, MAX_MSI_IRQS) = {};
+
+ ASSERT(spin_is_locked(&d->event_lock));
+
+@@ -1945,8 +1950,10 @@ int map_domain_pirq(
+ }
+
+ ret = prepare_domain_irq_pirq(d, irq, pirq, &info);
+- if ( ret )
++ if ( ret < 0 )
+ goto revoke;
++ if ( !ret )
++ __set_bit(0, prepared);
+
+ desc = irq_to_desc(irq);
+
+@@ -2018,8 +2025,10 @@ int map_domain_pirq(
+ irq = create_irq(NUMA_NO_NODE);
+ ret = irq >= 0 ? prepare_domain_irq_pirq(d, irq, pirq + nr, &info)
+ : irq;
+- if ( ret )
++ if ( ret < 0 )
+ break;
++ if ( !ret )
++ __set_bit(nr, prepared);
+ msi_desc[nr].irq = irq;
+
+ if ( irq_permit_access(d, irq) != 0 )
+@@ -2052,15 +2061,15 @@ int map_domain_pirq(
+ desc->msi_desc = NULL;
+ spin_unlock_irqrestore(&desc->lock, flags);
+ }
+- while ( nr-- )
++ while ( nr )
+ {
+ if ( irq >= 0 && irq_deny_access(d, irq) )
+ printk(XENLOG_G_ERR
+ "dom%d: could not revoke access to IRQ%d (pirq %d)\n",
+ d->domain_id, irq, pirq);
+- if ( info )
++ if ( info && test_bit(nr, prepared) )
+ cleanup_domain_irq_pirq(d, irq, info);
+- info = pirq_info(d, pirq + nr);
++ info = pirq_info(d, pirq + --nr);
+ irq = info->arch.irq;
+ }
+ msi_desc->irq = -1;
+@@ -2076,12 +2085,14 @@ int map_domain_pirq(
+ spin_lock_irqsave(&desc->lock, flags);
+ set_domain_irq_pirq(d, irq, info);
+ spin_unlock_irqrestore(&desc->lock, flags);
++ ret = 0;
+ }
+
+ done:
+ if ( ret )
+ {
+- cleanup_domain_irq_pirq(d, irq, info);
++ if ( test_bit(0, prepared) )
++ cleanup_domain_irq_pirq(d, irq, info);
+ revoke:
+ if ( irq_deny_access(d, irq) )
+ printk(XENLOG_G_ERR
+--- a/xen/arch/x86/physdev.c
++++ b/xen/arch/x86/physdev.c
+@@ -186,7 +186,7 @@ int physdev_map_pirq(domid_t domid, int
+ }
+ else if ( type == MAP_PIRQ_TYPE_MULTI_MSI )
+ {
+- if ( msi->entry_nr <= 0 || msi->entry_nr > 32 )
++ if ( msi->entry_nr <= 0 || msi->entry_nr > MAX_MSI_IRQS )
+ ret = -EDOM;
+ else if ( msi->entry_nr != 1 && !iommu_intremap )
+ ret = -EOPNOTSUPP;
+--- a/xen/include/asm-x86/msi.h
++++ b/xen/include/asm-x86/msi.h
+@@ -56,6 +56,8 @@
+ /* MAX fixed pages reserved for mapping MSIX tables. */
+ #define FIX_MSIX_MAX_PAGES 512
+
++#define MAX_MSI_IRQS 32 /* limited by MSI capability struct properties */
++
+ struct msi_info {
+ u16 seg;
+ u8 bus;