From mboxrd@z Thu Jan 1 00:00:00 1970 From: Julien Grall Subject: [PATCH v2 10/21] xen/arm: Implement hypercall PHYSDEVOP_{, un}map_pirq Date: Thu, 31 Jul 2014 16:00:41 +0100 Message-ID: <1406818852-31856-11-git-send-email-julien.grall@linaro.org> References: <1406818852-31856-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 1XCrr3-0000cD-KY for xen-devel@lists.xenproject.org; Thu, 31 Jul 2014 15:01:17 +0000 Received: by mail-we0-f169.google.com with SMTP id u56so2869653wes.28 for ; Thu, 31 Jul 2014 08:01:14 -0700 (PDT) In-Reply-To: <1406818852-31856-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 List-Id: xen-devel@lists.xenproject.org The physdev sub-hypercalls PHYSDEVOP_{,map}_pirq allow the toolstack to assign/deassign a physical IRQ to the guest (via the config options "irqs" for xl). For now, we allow only SPIs to be mapped to the guest. The type MAP_PIRQ_TYPE_GSI is used for this purpose. The virtual IRQ number is allocated by Xen. The toolstack as to specify the number of SPIs handled by the vGIC via an hypercall. Signed-off-by: Julien Grall --- I'm wondering if we should introduce an alias of MAP_PIRQ_TYPE_GSI for ARM. It's will be less confuse for the user. Changes in v2: - Add PHYSDEVOP_unmap_pirq - Rework commit message - Add functions to allocate/release a VIRQ - is_routable_irq has been renamed into is_assignable_irq --- xen/arch/arm/physdev.c | 120 +++++++++++++++++++++++++++++++++++++++++- xen/arch/arm/vgic.c | 51 ++++++++++++++++++ xen/include/asm-arm/domain.h | 1 + xen/include/asm-arm/vgic.h | 5 ++ 4 files changed, 175 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/physdev.c b/xen/arch/arm/physdev.c index 61b4a18..9333aa0 100644 --- a/xen/arch/arm/physdev.c +++ b/xen/arch/arm/physdev.c @@ -8,13 +8,129 @@ #include #include #include +#include +#include +#include +#include #include +#include +static int physdev_map_pirq(domid_t domid, int type, int index, int *pirq_p) +{ + struct domain *d; + int ret; + int irq = index; + int virq = 0; + + d = rcu_lock_domain_by_any_id(domid); + if ( d == NULL ) + return -ESRCH; + + ret = xsm_map_domain_pirq(XSM_TARGET, d); + if ( ret ) + goto free_domain; + + /* For now we only suport GSI */ + if ( type != MAP_PIRQ_TYPE_GSI ) + { + ret = -EINVAL; + dprintk(XENLOG_G_ERR, "dom%u: wrong map_pirq type 0x%x\n", + d->domain_id, type); + goto free_domain; + } + + if ( !is_assignable_irq(irq) ) + { + ret = -EINVAL; + dprintk(XENLOG_G_ERR, "IRQ%u is not routable to a guest\n", irq); + goto free_domain; + } + + ret = -EPERM; + if ( !irq_access_permitted(current->domain, irq) ) + goto free_domain; + + virq = vgic_allocate_virq(d, irq); + ret = -EMFILE; + if ( virq == -1 ) + goto free_domain; + + ret = route_irq_to_guest(d, virq, irq, "routed IRQ"); + + if ( !ret ) + *pirq_p = virq; + else + vgic_free_virq(d, virq); + +free_domain: + rcu_unlock_domain(d); + + return ret; +} + +int physdev_unmap_pirq(domid_t domid, int pirq) +{ + struct domain *d; + int ret; + + d = rcu_lock_domain_by_any_id(domid); + if ( d == NULL ) + return -ESRCH; + + ret = xsm_unmap_domain_pirq(XSM_TARGET, d); + if ( ret ) + goto free_domain; + + ret = release_guest_irq(d, pirq); + if ( ret ) + goto free_domain; + + vgic_free_virq(d, pirq); + +free_domain: + rcu_unlock_domain(d); + + return ret; +} 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; + + ret = -EFAULT; + if ( copy_from_guest(&map, arg, 1) != 0 ) + break; + + ret = physdev_map_pirq(map.domid, map.type, map.index, &map.pirq); + + if ( __copy_to_guest(arg, &map, 1) ) + ret = -EFAULT; + } + break; + + case PHYSDEVOP_unmap_pirq: + { + physdev_unmap_pirq_t unmap; + + ret = -EFAULT; + if ( copy_from_guest(&unmap, arg, 1) != 0 ) + break; + + ret = physdev_unmap_pirq(unmap.domid, unmap.pirq); + } + + default: + ret = -ENOSYS; + break; + } + + return ret; } /* diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 2a5fc18..644742e 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -81,6 +81,8 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) return -ENODEV; } + spin_lock_init(&d->arch.vgic.lock); + d->arch.vgic.shared_irqs = xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d)); if ( d->arch.vgic.shared_irqs == NULL ) @@ -108,6 +110,11 @@ int domain_vgic_init(struct domain *d, unsigned int nr_spis) d->arch.vgic.handler->domain_init(d); + d->arch.vgic.allocated_spis = + xzalloc_array(unsigned long, BITS_TO_LONGS(d->arch.vgic.nr_spis)); + if ( !d->arch.vgic.allocated_spis ) + return -ENOMEM; + return 0; } @@ -444,6 +451,50 @@ void arch_evtchn_inject(struct vcpu *v) vgic_vcpu_inject_irq(v, v->domain->arch.evtchn_irq); } +int vgic_allocate_virq(struct domain *d, unsigned int irq) +{ + unsigned int spi; + int virq = -1; + + /* Hardware domain has IRQ mapped 1:1 */ + if ( is_hardware_domain(d) ) + return irq; + + spin_lock(&d->arch.vgic.lock); + + spi = find_first_zero_bit(d->arch.vgic.allocated_spis, + d->arch.vgic.nr_spis); + + if ( spi >= d->arch.vgic.nr_spis ) + goto unlock; + + set_bit(spi, d->arch.vgic.allocated_spis); + + virq = 32 + spi; + +unlock: + spin_unlock(&d->arch.vgic.lock); + + return virq; +} + +void vgic_free_virq(struct domain *d, unsigned int virq) +{ + unsigned int spi; + + if ( is_hardware_domain(d) ) + return; + + if ( virq < 32 && virq >= vgic_num_irqs(d) ) + return; + + spi = virq - 32; + + spin_lock(&d->arch.vgic.lock); + clear_bit(spi, d->arch.vgic.allocated_spis); + spin_unlock(&d->arch.vgic.lock); +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 44727b2..a4039c1 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -94,6 +94,7 @@ struct arch_domain spinlock_t lock; int ctlr; int nr_spis; /* Number of SPIs */ + unsigned long *allocated_spis; /* bitmap of SPIs allocated */ struct vgic_irq_rank *shared_irqs; /* * SPIs are domain global, SGIs and PPIs are per-VCPU and stored in diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index 84ae441..c5d8b2e 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -180,6 +180,11 @@ extern int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, int virq, unsigned long vcpu_mask); extern void vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq); + +/* Allocate a VIRQ number of a guest SPI */ +extern int vgic_allocate_virq(struct domain *d, unsigned int irq); +extern void vgic_free_virq(struct domain *d, unsigned int irq); + #endif /* __ASM_ARM_VGIC_H__ */ /* -- 1.7.10.4