|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v4 3/4] xen/arm: vgic: free eSPIs using the bitmap index
The allocated_irqs bitmap in the existing vGIC implementation stores eSPI
allocation bits immediately after the regular vIRQ bits.
vgic_reserve_virq() converts an eSPI INTID to this compressed bitmap index,
but vgic_free_virq() used the raw INTID.
Freeing INTID 4096 therefore clears bit 4096 instead of the first eSPI bit.
This writes beyond allocated_irqs and leaves the intended eSPI bit set.
Valid eSPIs reach this path during DOMCTL bind failure cleanup and unbind,
and during vPL011 teardown.
Add virq_to_idx(), the inverse of idx_to_virq(), and use it when reserving
and freeing vIRQs. Validate a vIRQ before clearing its allocation bit.
Fixes: bdde400c6e1b ("xen/arm: vgic: add resource management for extended SPIs")
Signed-off-by: Mykola Kvach <mykola_kvach@xxxxxxxx>
Reviewed-by: Michal Orzel <michal.orzel@xxxxxxx>
---
Changes in v4:
- Document the compressed bitmap layout with an ASCII diagram above the
conversion helpers and refer to struct vgic_dist for the full layout.
Changes in v3:
- Adapt virq_to_idx() to the configuration-neutral is_espi() helper.
Changes in v2:
- Call is_espi() without a configuration guard.
---
xen/arch/arm/vgic.c | 42 +++++++++++++++++++++++++++++++-----------
1 file changed, 31 insertions(+), 11 deletions(-)
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index e04678f134..5b15b98ac3 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -25,6 +25,21 @@
#include <asm/vgic.h>
+/*
+ * The allocated_irqs bitmap is compressed: eSPI bits immediately follow
+ * regular IRQ bits, skipping the gap in the INTID space.
+ *
+ * +-----------+-----------+-------------------+-------------------+
+ * | SGIs | PPIs | SPIs | eSPIs |
+ * +-----------+-----------+-------------------+-------------------+
+ * 0 16 32 vgic_num_irqs(d)
+ *
+ * INTID ESPI_BASE_INTID maps to bitmap index vgic_num_irqs(d).
+ * The following idx_to_virq() and virq_to_idx() convert between INTIDs
+ * and bitmap indexes.
+ *
+ * See also the allocated_irqs comment in struct vgic_dist.
+ */
static inline unsigned int idx_to_virq(struct domain *d, unsigned int idx)
{
if ( idx >= vgic_num_irqs(d) )
@@ -33,6 +48,16 @@ static inline unsigned int idx_to_virq(struct domain *d,
unsigned int idx)
return idx;
}
+static inline unsigned int virq_to_idx(struct domain *d, unsigned int virq)
+{
+ ASSERT(IS_ENABLED(CONFIG_GICV3_ESPI) || !is_espi(virq));
+
+ if ( IS_ENABLED(CONFIG_GICV3_ESPI) && is_espi(virq) )
+ return espi_intid_to_idx(virq) + vgic_num_irqs(d);
+
+ return virq;
+}
+
bool vgic_is_valid_line(struct domain *d, unsigned int virq)
{
#ifdef CONFIG_GICV3_ESPI
@@ -850,19 +875,11 @@ bool vgic_emulate(struct cpu_user_regs *regs, union hsr
hsr)
bool vgic_reserve_virq(struct domain *d, unsigned int virq)
{
- unsigned int idx = virq;
-
if ( !vgic_is_valid_line(d, virq) )
return false;
- if ( is_espi(virq) )
- {
- unsigned int num_regular_irqs = vgic_num_irqs(d);
-
- idx = espi_intid_to_idx(virq) + num_regular_irqs;
- }
-
- return !test_and_set_bit(idx, d->arch.vgic.allocated_irqs);
+ return !test_and_set_bit(virq_to_idx(d, virq),
+ d->arch.vgic.allocated_irqs);
}
int vgic_allocate_virq(struct domain *d, bool spi)
@@ -899,7 +916,10 @@ int vgic_allocate_virq(struct domain *d, bool spi)
void vgic_free_virq(struct domain *d, unsigned int virq)
{
- clear_bit(virq, d->arch.vgic.allocated_irqs);
+ if ( !vgic_is_valid_line(d, virq) )
+ return;
+
+ clear_bit(virq_to_idx(d, virq), d->arch.vgic.allocated_irqs);
}
unsigned int vgic_max_vcpus(unsigned int domctl_vgic_version)
--
2.53.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |