|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [XenARM] XEN tools for ARM with Virtualization Extensions - Patch #2
Second patch submitted with changes based on comments on first patch.
> > From 551f174c9653def01890fadd2dd769ab8a9acde7 Mon Sep 17 00:00:00
> 2001
> > From: Eric Trudeau <etrudeau@xxxxxxxxxxxx>
> > Date: Thu, 11 Jul 2013 20:03:51 -0400
> > Subject: [PATCH] Add support for Guest physdev irqs
> >
> > ---
> > xen/arch/arm/domain.c | 16 ++++++++++++++++
> > xen/arch/arm/gic.c | 15 ++++++++++-----
> > xen/arch/arm/physdev.c | 48
> ++++++++++++++++++++++++++++++++++++++++++++++--
> > xen/arch/arm/vgic.c | 5 +----
> > 4 files changed, 73 insertions(+), 11 deletions(-)
> >
> > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> > index 4c434a1..52d3429 100644
> > --- a/xen/arch/arm/domain.c
> > +++ b/xen/arch/arm/domain.c
> > @@ -31,6 +31,8 @@
> > #include <asm/gic.h>
> > #include "vtimer.h"
> > #include "vpl011.h"
> > +#include <xen/iocap.h>
> > +#include <xen/irq.h>
> >
> > DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
> >
> > @@ -513,8 +515,22 @@ fail:
> > return rc;
> > }
> >
> > +static int release_domain_irqs(struct domain *d)
> > +{
> > + int i;
> > + for (i = 0; i <= d->nr_pirqs; i++) {
> > + if (irq_access_permitted(d, i)) {
> > + release_irq(i);
> > + }
> > + }
> > + return 0;
> > +}
>
> As you may know, release_irq will spin until the flags IRQ_INPROGRESS
> is unset. This is done my the maintenance handler.
>
> Now, let say the domain has crashed and the IRQ is not yet EOIed, then you
> will spin forever.
>
I put a timeout in the IRQ_INPROGRESS check in release_irq() of 100 attempts
with a 1 msec delay per loop iteration.
> > +
> > void arch_domain_destroy(struct domain *d)
> > {
> > + if (d->irq_caps != NULL)
> You don't need this check.
> During the domain create, Xen ensures that irq_caps is not NULL.
>
> > + release_domain_irqs(d);
> > p2m_teardown(d);
> > domain_vgic_free(d);
> > domain_uart0_free(d);
> > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> > index cafb681..1f576d1 100644
> > --- a/xen/arch/arm/gic.c
> > +++ b/xen/arch/arm/gic.c
> > @@ -510,7 +510,7 @@ void gic_route_spis(void)
> > }
> > }
> >
> > -void __init release_irq(unsigned int irq)
> > +void release_irq(unsigned int irq)
> > {
> > struct irq_desc *desc;
> > unsigned long flags;
> > @@ -522,6 +522,7 @@ void __init release_irq(unsigned int irq)
> > action = desc->action;
> > desc->action = NULL;
> > desc->status |= IRQ_DISABLED;
> > + desc->status &= ~IRQ_GUEST;
> >
> > spin_lock(&gic.lock);
> > desc->handler->shutdown(desc);
> > @@ -707,6 +708,12 @@ int gic_route_irq_to_guest(struct domain *d, const
> struct dt_irq *irq,
> > spin_lock_irqsave(&desc->lock, flags);
> > spin_lock(&gic.lock);
> >
> > + if ( desc->action != NULL )
> > + {
> > + retval = -EBUSY;
> > + goto out;
> > + }
> > +
> > desc->handler = &gic_guest_irq_type;
> > desc->status |= IRQ_GUEST;
> >
> > @@ -715,12 +722,10 @@ int gic_route_irq_to_guest(struct domain *d, const
> struct dt_irq *irq,
> > gic_set_irq_properties(irq->irq, level, 1u << smp_processor_id(),
> > 0xa0);
> >
> > retval = __setup_irq(desc, irq->irq, action);
> > - if (retval) {
> > - xfree(action);
> > - goto out;
> > - }
> >
> > out:
> > + if (retval)
> > + xfree(action);
> > spin_unlock(&gic.lock);
> > spin_unlock_irqrestore(&desc->lock, flags);
> > return retval;
> > diff --git a/xen/arch/arm/physdev.c b/xen/arch/arm/physdev.c
> > index 61b4a18..8a5f770 100644
> > --- a/xen/arch/arm/physdev.c
> > +++ b/xen/arch/arm/physdev.c
> > @@ -9,12 +9,56 @@
> > #include <xen/lib.h>
> > #include <xen/errno.h>
> > #include <asm/hypercall.h>
> > +#include <public/physdev.h>
> > +#include <xen/guest_access.h>
> > +#include <xen/irq.h>
> > +#include <xen/sched.h>
> > +#include <asm/gic.h>
> >
> >
> > int do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
> > {
> > - printk("%s %d cmd=%d: not implemented yet\n", __func__, __LINE__,
> cmd);
> > - return -ENOSYS;
> > + int ret;
> > +
> > + switch ( cmd )
> > + {
> > + case PHYSDEVOP_map_pirq: {
> > + physdev_map_pirq_t map;
> > + struct dt_irq irq;
> > + struct domain *d;
> > +
> > + ret = -EFAULT;
> > + if ( copy_from_guest(&map, arg, 1) != 0 )
> > + break;
> > +
> > + d = rcu_lock_domain_by_any_id(map.domid);
> > + if ( d == NULL ) {
> > + ret = -ESRCH;
> > + break;
> > + }
>
> Missing sanity check on the map.pirq value.
>
I added a check for (map.pirq < gic_number_lines()). This is the sanity check
that is done in gic_route_irq(). Should this be less than or equal or are the
device tree SPI irq numbers 0-based before they are offset by 32?
> > + irq.irq = map.pirq;
> > + irq.type = DT_IRQ_TYPE_LEVEL_MASK;
> > +
> > + ret = gic_route_irq_to_guest(d, &irq, "GuestIRQ");
>
> Do you plan to handle non 1:1 IRQ mapping?
> How does work your the IRQ mapping if the IRQ is already mapped to dom0?
>
See comment below about sticking with 1:1 irq mapping.
> > + if (!ret)
> > + printk("%s gic_route_irq_to_guest added IRQ %d to dom%d\n",
> > + __FUNCTION__, irq.irq, d->domain_id);
> > +
> > + rcu_unlock_domain(d);
> > +
> > + if (!ret && __copy_to_guest(arg, &map, 1) )
> > + ret = -EFAULT;
> > + break;
> > + }
> > +
> > + default:
> > + printk("%s %d cmd=%d: not implemented yet\n", __func__, __LINE__,
> cmd);
> > + ret = -ENOSYS;
> > + break;
> > + }
> > +
> > + return ret;
> > }
> >
> > /*
> > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> > index 2e4b11f..0ebcdac 100644
> > --- a/xen/arch/arm/vgic.c
> > +++ b/xen/arch/arm/vgic.c
> > @@ -82,10 +82,7 @@ int domain_vgic_init(struct domain *d)
> > /* Currently nr_lines in vgic and gic doesn't have the same meanings
> > * Here nr_lines = number of SPIs
> > */
> > - if ( d->domain_id == 0 )
> > - d->arch.vgic.nr_lines = gic_number_lines() - 32;
> > - else
> > - d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
> > + d->arch.vgic.nr_lines = d->nr_pirqs - 32;
>
> If you want to stick on the 1:1 mapping, the best solution
> is to set "nr_lines to gic_number_lines() - 32" for all the domains.
>
I will stick with 1:1 mapping for guest IRQs and use gic_number_lines() - 32.
> --
> Julien Grall
Patch #2 begins here:
--------------------------------------------
From 924441c3eddb1765cb4fb0e94f6b62177195837d Mon Sep 17 00:00:00 2001
From: Eric Trudeau <etrudeau@xxxxxxxxxxxx>
Date: Fri, 12 Jul 2013 14:54:24 -0400
Subject: [PATCH] xen/arm: Add support for 1:1 IRQ mapping into guest domains
on ARM
ARM guests will now have the ability to access 1:1 mapped IRQs.
The irqs list in the domain configuration file is used. A SPI irq
number must include the offset of 32. For example, if the device
tree irq number is 76 for a SPI, then the irqs field in the dom.cfg
file would be:
irqs = [ 108 ]
Only level-triggered IRQs are supported at this time.
When an IRQ is released on destruction of the guest, any in-progress
handlers are given at least a 100 msec to complete.
Signed-off-by: Eric Trudeau <etrudeau@xxxxxxxxxxxx>
---
xen/arch/arm/domain.c | 15 ++++++++++++++
xen/arch/arm/gic.c | 29 ++++++++++++++++++--------
xen/arch/arm/physdev.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++--
xen/arch/arm/vgic.c | 5 +----
4 files changed, 91 insertions(+), 14 deletions(-)
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 4c434a1..f15ff06 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -31,6 +31,8 @@
#include <asm/gic.h>
#include "vtimer.h"
#include "vpl011.h"
+#include <xen/iocap.h>
+#include <xen/irq.h>
DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
@@ -513,8 +515,21 @@ fail:
return rc;
}
+static int release_domain_irqs(struct domain *d)
+{
+ int i;
+ for (i = 0; i <= d->nr_pirqs; i++) {
+ if (irq_access_permitted(d, i)) {
+ release_irq(i);
+ }
+ }
+ return 0;
+}
+
+
void arch_domain_destroy(struct domain *d)
{
+ release_domain_irqs(d);
p2m_teardown(d);
domain_vgic_free(d);
domain_uart0_free(d);
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index ccce565..ed15ec3 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -30,6 +30,7 @@
#include <xen/device_tree.h>
#include <asm/p2m.h>
#include <asm/domain.h>
+#include <xen/delay.h>
#include <asm/gic.h>
@@ -510,11 +511,12 @@ void gic_route_spis(void)
}
}
-void __init release_irq(unsigned int irq)
+void release_irq(unsigned int irq)
{
struct irq_desc *desc;
unsigned long flags;
- struct irqaction *action;
+ struct irqaction *action;
+ int inprogresschecks;
desc = irq_to_desc(irq);
@@ -530,8 +532,15 @@ void __init release_irq(unsigned int irq)
spin_unlock_irqrestore(&desc->lock,flags);
- /* Wait to make sure it's not being used on another CPU */
- do { smp_mb(); } while ( desc->status & IRQ_INPROGRESS );
+ /* Wait a little while to make sure it's not being used on another CPU
+ * But not indefinitely, because a guest may have crashed */
+ for (inprogresschecks = 0; (inprogresschecks < 100); inprogresschecks++) {
+ smp_mb();
+ if ( desc->status & IRQ_INPROGRESS )
+ mdelay(1);
+ else
+ break;
+ }
if (action && action->free_on_release)
xfree(action);
@@ -708,6 +717,12 @@ int gic_route_irq_to_guest(struct domain *d, const struct
dt_irq *irq,
spin_lock_irqsave(&desc->lock, flags);
spin_lock(&gic.lock);
+ if ( desc->action != NULL )
+ {
+ retval = -EBUSY;
+ goto out;
+ }
+
desc->handler = &gic_guest_irq_type;
desc->status |= IRQ_GUEST;
@@ -716,12 +731,10 @@ int gic_route_irq_to_guest(struct domain *d, const struct
dt_irq *irq,
gic_set_irq_properties(irq->irq, level, 1u << smp_processor_id(), 0xa0);
retval = __setup_irq(desc, irq->irq, action);
- if (retval) {
- xfree(action);
- goto out;
- }
out:
+ if (retval)
+ xfree(action);
spin_unlock(&gic.lock);
spin_unlock_irqrestore(&desc->lock, flags);
return retval;
diff --git a/xen/arch/arm/physdev.c b/xen/arch/arm/physdev.c
index 61b4a18..8d76d11 100644
--- a/xen/arch/arm/physdev.c
+++ b/xen/arch/arm/physdev.c
@@ -9,12 +9,64 @@
#include <xen/lib.h>
#include <xen/errno.h>
#include <asm/hypercall.h>
+#include <public/physdev.h>
+#include <xen/guest_access.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <asm/gic.h>
+#include <xsm/xsm.h>
int do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
{
- printk("%s %d cmd=%d: not implemented yet\n", __func__, __LINE__, cmd);
- return -ENOSYS;
+ int ret;
+
+ switch ( cmd )
+ {
+ case PHYSDEVOP_map_pirq: {
+ physdev_map_pirq_t map;
+ struct dt_irq irq;
+ struct domain *d;
+
+ ret = -EFAULT;
+ if ( copy_from_guest(&map, arg, 1) != 0 )
+ break;
+
+ d = rcu_lock_domain_by_any_id(map.domid);
+ if ( d == NULL ) {
+ ret = -ESRCH;
+ break;
+ }
+
+ ret = xsm_map_domain_pirq(XSM_TARGET, d);
+
+ if (!ret && (map.pirq >= gic_number_lines()))
+ ret = -EINVAL;
+
+ if (!ret) {
+ irq.irq = map.pirq;
+ irq.type = DT_IRQ_TYPE_LEVEL_MASK;
+
+ ret = gic_route_irq_to_guest(d, &irq, "GuestIRQ");
+ if (!ret)
+ dprintk(XENLOG_G_INFO, "dom%d: gic_route_irq_to_guest mapped
in IRQ %d\n",
+ d->domain_id, irq.irq);
+ }
+
+ rcu_unlock_domain(d);
+
+ if (!ret && __copy_to_guest(arg, &map, 1) )
+ ret = -EFAULT;
+ break;
+ }
+
+ default:
+ printk("%s %d cmd=%d: not implemented yet\n", __func__, __LINE__, cmd);
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
}
/*
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 2e4b11f..9c95f67 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -82,10 +82,7 @@ int domain_vgic_init(struct domain *d)
/* Currently nr_lines in vgic and gic doesn't have the same meanings
* Here nr_lines = number of SPIs
*/
- if ( d->domain_id == 0 )
- d->arch.vgic.nr_lines = gic_number_lines() - 32;
- else
- d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
+ d->arch.vgic.nr_lines = gic_number_lines() - 32;
d->arch.vgic.shared_irqs =
xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d));
--
1.8.1.2
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |