From mboxrd@z Thu Jan 1 00:00:00 1970 From: Julien Grall Subject: [PATCH v4 12/33] xen/arm: gic: Add sanity checks gic_route_irq_to_guest Date: Thu, 19 Mar 2015 19:29:38 +0000 Message-ID: <1426793399-6283-13-git-send-email-julien.grall@linaro.org> References: <1426793399-6283-1-git-send-email-julien.grall@linaro.org> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1YYg9h-0004NY-7c for xen-devel@lists.xenproject.org; Thu, 19 Mar 2015 19:30:57 +0000 Received: by webcq43 with SMTP id cq43so65662548web.2 for ; Thu, 19 Mar 2015 12:30:55 -0700 (PDT) In-Reply-To: <1426793399-6283-1-git-send-email-julien.grall@linaro.org> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xenproject.org Cc: stefano.stabellini@citrix.com, Julien Grall , tim@xen.org, ian.campbell@citrix.com, Stefano Stabellini List-Id: xen-devel@lists.xenproject.org With the addition of interrupt assignment to guest, we need to make sure the guest can't blow up the interrupt management in Xen. Before associating the IRQ to a vIRQ we need to make sure: - the vIRQ is not already associated to another IRQ - the guest didn't enable the vIRQ Signed-off-by: Julien Grall Acked-by: Stefano Stabellini --- Changes in v4: - Move functional change (GIC_IRQ_PRI -> priority) in a separate patch. - Split the 2 conditions of the ASSERT in 2 different ASSERTs - Typoes - Add Stefano's ack Changes in v3: - Patch added --- xen/arch/arm/gic.c | 35 +++++++++++++++++++++++++++-------- xen/arch/arm/irq.c | 12 ++++++++++-- xen/include/asm-arm/gic.h | 7 +++---- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index fe8f69b..2709415 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -126,22 +126,41 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask, /* Program the GIC to route an interrupt to a guest * - desc.lock must be held */ -void gic_route_irq_to_guest(struct domain *d, unsigned int virq, - struct irq_desc *desc, - const cpumask_t *cpu_mask, unsigned int priority) +int gic_route_irq_to_guest(struct domain *d, unsigned int virq, + struct irq_desc *desc, unsigned int priority) { - struct pending_irq *p; + unsigned long flags; + /* Use vcpu0 to retrieve the pending_irq struct. Given that we only + * route SPIs to guests, it doesn't make any difference. */ + struct vcpu *v_target = vgic_get_target_vcpu(d->vcpu[0], virq); + struct vgic_irq_rank *rank = vgic_rank_irq(v_target, virq); + struct pending_irq *p = irq_to_pending(v_target, virq); + int res = -EBUSY; + ASSERT(spin_is_locked(&desc->lock)); + /* Caller has already checked that the IRQ is an SPI */ + ASSERT(virq >= 32); + ASSERT(virq < vgic_num_irqs(d)); + + vgic_lock_rank(v_target, rank, flags); + + if ( p->desc || + /* The VIRQ should not be already enabled by the guest */ + test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) ) + goto out; desc->handler = gic_hw_ops->gic_guest_irq_type; set_bit(_IRQ_GUEST, &desc->status); - gic_set_irq_properties(desc, cpumask_of(smp_processor_id()), GIC_PRI_IRQ); + gic_set_irq_properties(desc, cpumask_of(v_target->processor), GIC_PRI_IRQ); - /* Use vcpu0 to retrieve the pending_irq struct. Given that we only - * route SPIs to guests, it doesn't make any difference. */ - p = irq_to_pending(d->vcpu[0], virq); p->desc = desc; + res = 0; + +out: + vgic_unlock_rank(v_target, rank, flags); + + return res; } int gic_irq_xlate(const u32 *intspec, unsigned int intsize, diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c index 4c3e381..b2ddf6b 100644 --- a/xen/arch/arm/irq.c +++ b/xen/arch/arm/irq.c @@ -492,14 +492,22 @@ int route_irq_to_guest(struct domain *d, unsigned int virq, if ( retval ) goto out; - gic_route_irq_to_guest(d, virq, desc, cpumask_of(smp_processor_id()), - GIC_PRI_IRQ); + retval = gic_route_irq_to_guest(d, virq, desc, GIC_PRI_IRQ); + spin_unlock_irqrestore(&desc->lock, flags); + + if ( retval ) + { + release_irq(desc->irq, info); + goto free_info; + } + return 0; out: spin_unlock_irqrestore(&desc->lock, flags); xfree(action); +free_info: xfree(info); return retval; diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index bb2a922..ef4bf9a 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -216,10 +216,9 @@ extern enum gic_version gic_hw_version(void); /* Program the GIC to route an interrupt */ extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mask, unsigned int priority); -extern void gic_route_irq_to_guest(struct domain *, unsigned int virq, - struct irq_desc *desc, - const cpumask_t *cpu_mask, - unsigned int priority); +extern int gic_route_irq_to_guest(struct domain *, unsigned int virq, + struct irq_desc *desc, + unsigned int priority); extern void gic_inject(void); extern void gic_clear_pending_irqs(struct vcpu *v); -- 2.1.4