summaryrefslogtreecommitdiff
blob: f7f61e873afd16b9be862a644cae53215aac1eb4 (plain)
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
From 30c695ddaf067cbe7a98037474e7910109238807 Mon Sep 17 00:00:00 2001
From: Jan Beulich <jbeulich@suse.com>
Date: Thu, 4 Jul 2024 14:14:16 +0200
Subject: [PATCH 50/56] cmdline: document and enforce "extra_guest_irqs" upper
 bounds
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

PHYSDEVOP_pirq_eoi_gmfn_v<N> accepting just a single GFN implies that no
more than 32k pIRQ-s can be used by a domain on x86. Document this upper
bound.

To also enforce the limit, (ab)use both arch_hwdom_irqs() (changing its
parameter type) and setup_system_domains(). This is primarily to avoid
exposing the two static variables or introducing yet further arch hooks.

While touching arch_hwdom_irqs() also mark it hwdom-init.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Roger Pau Monné <roger.pau@citrix.com>

amend 'cmdline: document and enforce "extra_guest_irqs" upper bounds'

Address late review comments for what is now commit 17f6d398f765:
- bound max_irqs right away against nr_irqs
- introduce a #define for a constant used twice

Requested-by: Roger Pau Monné <roger.pau@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
master commit: 17f6d398f76597f8009ec0530842fb8705ece7ba
master date: 2024-07-02 12:00:27 +0200
master commit: 1f56accba33ffea0abf7d1c6384710823d10cbd6
master date: 2024-07-03 14:03:27 +0200
---
 docs/misc/xen-command-line.pandoc |  3 ++-
 xen/arch/x86/io_apic.c            | 17 ++++++++++-------
 xen/common/domain.c               | 24 ++++++++++++++++++++++--
 xen/include/xen/irq.h             |  3 ++-
 4 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc
index 10a09bbf23..d857bd0f89 100644
--- a/docs/misc/xen-command-line.pandoc
+++ b/docs/misc/xen-command-line.pandoc
@@ -1175,7 +1175,8 @@ common for all domUs, while the optional second number (preceded by a comma)
 is for dom0.  Changing the setting for domU has no impact on dom0 and vice
 versa.  For example to change dom0 without changing domU, use
 `extra_guest_irqs=,512`.  The default value for Dom0 and an eventual separate
-hardware domain is architecture dependent.
+hardware domain is architecture dependent.  The upper limit for both values on
+x86 is such that the resulting total number of IRQs can't be higher than 32768.
 Note that specifying zero as domU value means zero, while for dom0 it means
 to use the default.
 
diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c
index c5342789e8..f7591fd091 100644
--- a/xen/arch/x86/io_apic.c
+++ b/xen/arch/x86/io_apic.c
@@ -2664,18 +2664,21 @@ void __init ioapic_init(void)
            nr_irqs_gsi, nr_irqs - nr_irqs_gsi);
 }
 
-unsigned int arch_hwdom_irqs(domid_t domid)
+unsigned int __hwdom_init arch_hwdom_irqs(const struct domain *d)
 {
     unsigned int n = fls(num_present_cpus());
+    /* Bounding by the domain pirq EOI bitmap capacity. */
+    const unsigned int max_irqs = min_t(unsigned int, nr_irqs,
+                                        PAGE_SIZE * BITS_PER_BYTE);
 
-    if ( !domid )
-        n = min(n, dom0_max_vcpus());
-    n = min(nr_irqs_gsi + n * NR_DYNAMIC_VECTORS, nr_irqs);
+    if ( is_system_domain(d) )
+        return max_irqs;
 
-    /* Bounded by the domain pirq eoi bitmap gfn. */
-    n = min_t(unsigned int, n, PAGE_SIZE * BITS_PER_BYTE);
+    if ( !d->domain_id )
+        n = min(n, dom0_max_vcpus());
+    n = min(nr_irqs_gsi + n * NR_DYNAMIC_VECTORS, max_irqs);
 
-    printk("Dom%d has maximum %u PIRQs\n", domid, n);
+    printk("%pd has maximum %u PIRQs\n", d, n);
 
     return n;
 }
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 003f4ab125..62832a5860 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -351,7 +351,8 @@ static int late_hwdom_init(struct domain *d)
 }
 
 static unsigned int __read_mostly extra_hwdom_irqs;
-static unsigned int __read_mostly extra_domU_irqs = 32;
+#define DEFAULT_EXTRA_DOMU_IRQS 32U
+static unsigned int __read_mostly extra_domU_irqs = DEFAULT_EXTRA_DOMU_IRQS;
 
 static int __init cf_check parse_extra_guest_irqs(const char *s)
 {
@@ -688,7 +689,7 @@ struct domain *domain_create(domid_t domid,
             d->nr_pirqs = nr_static_irqs + extra_domU_irqs;
         else
             d->nr_pirqs = extra_hwdom_irqs ? nr_static_irqs + extra_hwdom_irqs
-                                           : arch_hwdom_irqs(domid);
+                                           : arch_hwdom_irqs(d);
         d->nr_pirqs = min(d->nr_pirqs, nr_irqs);
 
         radix_tree_init(&d->pirq_tree);
@@ -812,6 +813,25 @@ void __init setup_system_domains(void)
     if ( IS_ERR(dom_xen) )
         panic("Failed to create d[XEN]: %ld\n", PTR_ERR(dom_xen));
 
+#ifdef CONFIG_HAS_PIRQ
+    /* Bound-check values passed via "extra_guest_irqs=". */
+    {
+        unsigned int n = max(arch_hwdom_irqs(dom_xen), nr_static_irqs);
+
+        if ( extra_hwdom_irqs > n - nr_static_irqs )
+        {
+            extra_hwdom_irqs = n - nr_static_irqs;
+            printk(XENLOG_WARNING "hwdom IRQs bounded to %u\n", n);
+        }
+        if ( extra_domU_irqs >
+             max(DEFAULT_EXTRA_DOMU_IRQS, n - nr_static_irqs) )
+        {
+            extra_domU_irqs = n - nr_static_irqs;
+            printk(XENLOG_WARNING "domU IRQs bounded to %u\n", n);
+        }
+    }
+#endif
+
     /*
      * Initialise our DOMID_IO domain.
      * This domain owns I/O pages that are within the range of the page_info
diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h
index 5dcd2d8f0c..bef170bcb6 100644
--- a/xen/include/xen/irq.h
+++ b/xen/include/xen/irq.h
@@ -196,8 +196,9 @@ extern struct irq_desc *pirq_spin_lock_irq_desc(
 
 unsigned int set_desc_affinity(struct irq_desc *desc, const cpumask_t *mask);
 
+/* When passed a system domain, this returns the maximum permissible value. */
 #ifndef arch_hwdom_irqs
-unsigned int arch_hwdom_irqs(domid_t domid);
+unsigned int arch_hwdom_irqs(const struct domain *d);
 #endif
 
 #ifndef arch_evtchn_bind_pirq
-- 
2.45.2