1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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;
|