[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] xen/arm: IRQ: Do not allow IRQ to be shared between domains and XEN



commit dcdcd3fe0f259892510c5ef8c7e2e0f9df09ba4b
Author:     Julien Grall <julien.grall@xxxxxxxxxx>
AuthorDate: Tue Apr 22 13:58:44 2014 +0100
Commit:     Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Fri May 2 13:14:09 2014 +0100

    xen/arm: IRQ: Do not allow IRQ to be shared between domains and XEN
    
    The current dt_route_irq_to_guest implementation sets IRQ_GUEST even if the
    IRQ is correctly setup.
    
    An IRQ can be shared between devices, if the devices are not assigned to the
    same domain or Xen, then this could result in routing the IRQ to the domain
    instead of Xen ...
    
    Also avoid to relying on wrong the behaviour when Xen is routing an IRQ to
    DOM0. Therefore check the return code from route_dt_irq_to_guest in
    map_device.
    
    Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>
    Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
 xen/arch/arm/domain_build.c |    9 +++++++--
 xen/arch/arm/irq.c          |   41 +++++++++++++++++++++++++++++++++++++----
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 5b636c8..9dcff1c 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -725,8 +725,13 @@ static int map_device(struct domain *d, const struct 
dt_device_node *dev)
         }
 
         DPRINT("irq %u = %u type = 0x%x\n", i, irq.irq, irq.type);
-        /* Don't check return because the IRQ can be use by multiple device */
-        route_dt_irq_to_guest(d, &irq, dt_node_name(dev));
+        res = route_dt_irq_to_guest(d, &irq, dt_node_name(dev));
+        if ( res )
+        {
+            printk(XENLOG_ERR "Unable to route IRQ %u to domain %u\n",
+                   irq.irq, d->domain_id);
+            return res;
+        }
     }
 
     /* Map the address ranges */
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 9f1ca40..44696e7 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -256,6 +256,16 @@ int setup_dt_irq(const struct dt_irq *irq, struct 
irqaction *new)
 
     spin_lock_irqsave(&desc->lock, flags);
 
+    if ( desc->status & IRQ_GUEST )
+    {
+        struct domain *d = irq_get_domain(desc);
+
+        spin_unlock_irqrestore(&desc->lock, flags);
+        printk(XENLOG_ERR "ERROR: IRQ %u is already in use by the domain %u\n",
+               irq->irq, d->domain_id);
+        return -EBUSY;
+    }
+
     disabled = (desc->action == NULL);
 
     rc = __setup_irq(desc, new);
@@ -292,7 +302,7 @@ int route_dt_irq_to_guest(struct domain *d, const struct 
dt_irq *irq,
     struct irqaction *action;
     struct irq_desc *desc = irq_to_desc(irq->irq);
     unsigned long flags;
-    int retval;
+    int retval = 0;
     bool_t level;
 
     action = xmalloc(struct irqaction);
@@ -305,19 +315,42 @@ int route_dt_irq_to_guest(struct domain *d, const struct 
dt_irq *irq,
 
     spin_lock_irqsave(&desc->lock, flags);
 
-    retval = __setup_irq(desc, action);
-    if ( retval )
+    /* If the IRQ is already used by someone
+     *  - If it's the same domain -> Xen doesn't need to update the IRQ desc
+     *  - Otherwise -> For now, don't allow the IRQ to be shared between
+     *  Xen and domains.
+     */
+    if ( desc->action != NULL )
     {
-        xfree(action);
+        struct domain *ad = irq_get_domain(desc);
+
+        if ( (desc->status & IRQ_GUEST) && d == ad )
+            goto out;
+
+        if ( desc->status & IRQ_GUEST )
+            printk(XENLOG_ERR "ERROR: IRQ %u is already used by domain %u\n",
+                   irq->irq, ad->domain_id);
+        else
+            printk(XENLOG_ERR "ERROR: IRQ %u is already used by Xen\n",
+                   irq->irq);
+        retval = -EBUSY;
         goto out;
     }
 
+    retval = __setup_irq(desc, action);
+    if ( retval )
+        goto out;
+
     level = dt_irq_is_level_triggered(irq);
     gic_route_irq_to_guest(d, desc, level, cpumask_of(smp_processor_id()),
                            GIC_PRI_IRQ);
+    spin_unlock_irqrestore(&desc->lock, flags);
+    return 0;
 
 out:
     spin_unlock_irqrestore(&desc->lock, flags);
+    xfree(action);
+
     return retval;
 }
 
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.