From mboxrd@z Thu Jan 1 00:00:00 1970 From: vijay.kilari@gmail.com Subject: [RFC PATCH v1 07/10] xen/arm: split vgic into generic and GIC v2 specific drivers Date: Wed, 19 Mar 2014 19:47:08 +0530 Message-ID: <1395238631-2024-8-git-send-email-vijay.kilari@gmail.com> References: <1395238631-2024-1-git-send-email-vijay.kilari@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1395238631-2024-1-git-send-email-vijay.kilari@gmail.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: Ian.Campbell@citrix.com, julien.grall@linaro.org, stefano.stabellini@eu.citrix.com, stefano.stabellini@citrix.com, xen-devel@lists.xen.org Cc: Prasun.Kapoor@caviumnetworks.com, Vijaya Kumar K , vijay.kilari@gmail.com List-Id: xen-devel@lists.xenproject.org From: Vijaya Kumar K vgic driver contains both generic and GIC v2 specific funtionality together. Segregate vgic driver into generic code into vgic.c and GIC v2 specific functionality into vgic-v2.c files. This helps to and GIC v3 specific funtionality. Signed-off-by: Vijaya Kumar K --- xen/arch/arm/Makefile | 2 +- xen/arch/arm/vgic-v2.c | 636 ++++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/vgic.c | 640 ++++----------------------------------------- xen/include/asm-arm/gic.h | 9 + 4 files changed, 695 insertions(+), 592 deletions(-) diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 969ee52..20f59f4 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -26,7 +26,7 @@ obj-y += smpboot.o obj-y += smp.o obj-y += shutdown.o obj-y += traps.o -obj-y += vgic.o +obj-y += vgic.o vgic-v2.o obj-y += vtimer.o obj-y += vuart.o obj-y += hvm.o diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c new file mode 100644 index 0000000..1e69763 --- /dev/null +++ b/xen/arch/arm/vgic-v2.c @@ -0,0 +1,636 @@ +/* + * xen/arch/arm/vgic-v2.c + * + * ARM Virtual Generic Interrupt Controller support v2 + * + * Ian Campbell + * Copyright (c) 2011 Citrix Systems. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "io.h" +#include +#include + +struct vgic_irq_rank { + spinlock_t lock; /* Covers access to all other members of this struct */ + uint32_t ienable, iactive, ipend, pendsgi; + uint32_t icfg[2]; + uint32_t ipriority[8]; + uint32_t itargets[8]; +}; + +#define REG(n) (n/4) + +/* Number of ranks of interrupt registers for a domain */ +#define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32) + +/* + * Rank containing GICD_ for GICD_ with + * -bits-per-interrupt + */ +static inline int REG_RANK_NR(int b, uint32_t n) +{ + switch ( b ) + { + case 8: return n >> 3; + case 4: return n >> 2; + case 2: return n >> 1; + case 1: return n; + default: BUG(); + } +} + +/* + * Offset of GICD_ with its rank, for GICD_ with + * -bits-per-interrupt. + */ +#define REG_RANK_INDEX(b, n) ((n) & ((b)-1)) + +/* + * Returns rank corresponding to a GICD_ register for + * GICD_ with -bits-per-interrupt. + */ +static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n) +{ + int rank = REG_RANK_NR(b, n); + + if ( rank == 0 ) + return (struct vgic_irq_rank *)v->arch.vgic.private_irqs; + else if ( rank <= DOMAIN_NR_RANKS(v->domain) ) + return (struct vgic_irq_rank *)((unsigned char *)(v->domain->arch.vgic.shared_irqs) + + (sizeof(struct vgic_irq_rank) *(rank - 1))); + else + return NULL; +} + +static uint32_t byte_read(uint32_t val, int sign, int offset) +{ + int byte = offset & 0x3; + + val = val >> (8*byte); + if ( sign && (val & 0x80) ) + val |= 0xffffff00; + else + val &= 0x000000ff; + return val; +} + +static void byte_write(uint32_t *reg, uint32_t var, int offset) +{ + int byte = offset & 0x3; + + var &= (0xff << (8*byte)); + + *reg &= ~(0xff << (8*byte)); + *reg |= var; +} + +static int vgic_read_priority(struct vcpu *v, int irq) +{ + int idx = irq >> 2; + struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, idx); + return byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, irq & 0x3); +} + +static int vgic_vcpu_init(struct vcpu *v) +{ + int i; + struct vgic_irq_rank *vir; + + vir = xzalloc(struct vgic_irq_rank); + memset(vir, 0, sizeof(struct vgic_irq_rank)); + + spin_lock_init(&vir->lock); + + /* For SGI and PPI the target is always this CPU */ + for ( i = 0 ; i < 8 ; i++ ) + vir->itargets[i] = + (1<<(v->vcpu_id+0)) + | (1<<(v->vcpu_id+8)) + | (1<<(v->vcpu_id+16)) + | (1<<(v->vcpu_id+24)); + + v->arch.vgic.private_irqs = (struct vgic_irq_irank *)vir; + return 0; +} + +static struct vgic_ops ops = { + .vgic_vcpu_init = vgic_vcpu_init, + .read_priority = vgic_read_priority, +}; + +#define vgic_lock(v) spin_lock_irq(&(v)->domain->arch.vgic.lock) +#define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock) + +#define vgic_lock_rank(v, r) spin_lock(&(r)->lock) +#define vgic_unlock_rank(v, r) spin_unlock(&(r)->lock) + +static int vgic_distr_mmio_read(struct vcpu *v, mmio_info_t *info) +{ + struct hsr_dabt dabt = info->dabt; + struct cpu_user_regs *regs = guest_cpu_user_regs(); + register_t *r = select_user_reg(regs, dabt.reg); + struct vgic_irq_rank *rank; + int offset = (int)(info->gpa - v->domain->arch.vgic.dbase); + int gicd_reg = REG(offset); + + switch ( gicd_reg ) + { + case GICD_CTLR: + if ( dabt.size != 2 ) goto bad_width; + vgic_lock(v); + *r = v->domain->arch.vgic.ctlr; + vgic_unlock(v); + return 1; + case GICD_TYPER: + if ( dabt.size != 2 ) goto bad_width; + /* No secure world support for guests. */ + vgic_lock(v); + *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS ) + |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES ); + vgic_unlock(v); + return 1; + case GICD_IIDR: + if ( dabt.size != 2 ) goto bad_width; + /* + * XXX Do we need a JEP106 manufacturer ID? + * Just use the physical h/w value for now + */ + *r = 0x0000043b; + return 1; + + /* Implementation defined -- read as zero */ + case REG(0x020) ... REG(0x03c): + goto read_as_zero; + + case GICD_IGROUPR ... GICD_IGROUPRN: + /* We do not implement security extensions for guests, read zero */ + goto read_as_zero; + + case GICD_ISENABLER ... GICD_ISENABLERN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = rank->ienable; + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ICENABLER ... GICD_ICENABLERN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = rank->ienable; + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ISPENDR ... GICD_ISPENDRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISPENDR); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = byte_read(rank->ipend, dabt.sign, offset); + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ICPENDR ... GICD_ICPENDRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICPENDR); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = byte_read(rank->ipend, dabt.sign, offset); + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ISACTIVER ... GICD_ISACTIVERN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = rank->iactive; + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ICACTIVER ... GICD_ICACTIVERN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = rank->iactive; + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ITARGETSR ... GICD_ITARGETSRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR); + if ( rank == NULL) goto read_as_zero; + + vgic_lock_rank(v, rank); + *r = rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)]; + if ( dabt.size == 0 ) + *r = byte_read(*r, dabt.sign, offset); + vgic_unlock_rank(v, rank); + return 1; + + case GICD_IPRIORITYR ... GICD_IPRIORITYRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR); + if ( rank == NULL) goto read_as_zero; + + vgic_lock_rank(v, rank); + *r = rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)]; + if ( dabt.size == 0 ) + *r = byte_read(*r, dabt.sign, offset); + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ICFGR ... GICD_ICFGRN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)]; + vgic_unlock_rank(v, rank); + return 1; + + case GICD_NSACR ... GICD_NSACRN: + /* We do not implement security extensions for guests, read zero */ + goto read_as_zero; + + case GICD_SGIR: + if ( dabt.size != 2 ) goto bad_width; + /* Write only -- read unknown */ + *r = 0xdeadbeef; + return 1; + + case GICD_CPENDSGIR ... GICD_CPENDSGIRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_CPENDSGIR); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = byte_read(rank->pendsgi, dabt.sign, offset); + vgic_unlock_rank(v, rank); + return 1; + + case GICD_SPENDSGIR ... GICD_SPENDSGIRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_SPENDSGIR); + if ( rank == NULL) goto read_as_zero; + vgic_lock_rank(v, rank); + *r = byte_read(rank->pendsgi, dabt.sign, offset); + vgic_unlock_rank(v, rank); + return 1; + + /* Implementation defined -- read as zero */ + case REG(0xfd0) ... REG(0xfe4): + goto read_as_zero; + + case GICD_ICPIDR2: + if ( dabt.size != 2 ) goto bad_width; + printk("vGICD: unhandled read from ICPIDR2\n"); + return 0; + + /* Implementation defined -- read as zero */ + case REG(0xfec) ... REG(0xffc): + goto read_as_zero; + + /* Reserved -- read as zero */ + case REG(0x00c) ... REG(0x01c): + case REG(0x040) ... REG(0x07c): + case REG(0x7fc): + case REG(0xbfc): + case REG(0xf04) ... REG(0xf0c): + case REG(0xf30) ... REG(0xfcc): + goto read_as_zero; + + default: + printk("vGICD: unhandled read r%d offset %#08x\n", + dabt.reg, offset); + return 0; + } + +bad_width: + printk("vGICD: bad read width %d r%d offset %#08x\n", + dabt.size, dabt.reg, offset); + domain_crash_synchronous(); + return 0; + +read_as_zero: + if ( dabt.size != 2 ) goto bad_width; + *r = 0; + return 1; +} + +static inline int is_vcpu_running(struct domain *d, int vcpuid) +{ + struct vcpu *v; + + if ( vcpuid >= d->max_vcpus ) + return 0; + + v = d->vcpu[vcpuid]; + if ( v == NULL ) + return 0; + if (test_bit(_VPF_down, &v->pause_flags) ) + return 0; + + return 1; +} + +static int vgic_to_sgi(struct vcpu *v, register_t sgir) +{ + struct domain *d = v->domain; + int virtual_irq; + int filter; + int vcpuid; + int i; + unsigned long vcpu_mask = 0; + + ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask)); + + filter = (sgir & GICD_SGI_TARGET_LIST_MASK); + virtual_irq = (sgir & GICD_SGI_INTID_MASK); + ASSERT( virtual_irq < 16 ); + + switch ( filter ) + { + case GICD_SGI_TARGET_LIST: + vcpu_mask = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT; + break; + case GICD_SGI_TARGET_OTHERS: + for ( i = 0; i < d->max_vcpus; i++ ) + { + if ( i != current->vcpu_id && is_vcpu_running(d, i) ) + set_bit(i, &vcpu_mask); + } + break; + case GICD_SGI_TARGET_SELF: + set_bit(current->vcpu_id, &vcpu_mask); + break; + default: + gdprintk(XENLOG_WARNING, "vGICD: unhandled GICD_SGIR write %"PRIregister" with wrong TargetListFilter field\n", + sgir); + return 0; + } + + for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus ) + { + if ( !is_vcpu_running(d, vcpuid) ) + { + gdprintk(XENLOG_WARNING, "vGICD: GICD_SGIR write r=%"PRIregister" vcpu_mask=%lx, wrong CPUTargetList\n", + sgir, vcpu_mask); + continue; + } + vgic_vcpu_inject_irq(d->vcpu[vcpuid], virtual_irq, 1); + } + return 1; +} + +static int vgic_distr_mmio_write(struct vcpu *v, mmio_info_t *info) +{ + struct hsr_dabt dabt = info->dabt; + struct cpu_user_regs *regs = guest_cpu_user_regs(); + register_t *r = select_user_reg(regs, dabt.reg); + struct vgic_irq_rank *rank; + int offset = (int)(info->gpa - v->domain->arch.vgic.dbase); + int gicd_reg = REG(offset); + uint32_t tr; + + switch ( gicd_reg ) + { + case GICD_CTLR: + if ( dabt.size != 2 ) goto bad_width; + /* Ignore all but the enable bit */ + v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE; + return 1; + + /* R/O -- write ignored */ + case GICD_TYPER: + case GICD_IIDR: + goto write_ignore; + + /* Implementation defined -- write ignored */ + case REG(0x020) ... REG(0x03c): + goto write_ignore; + + case GICD_IGROUPR ... GICD_IGROUPRN: + /* We do not implement security extensions for guests, write ignore */ + goto write_ignore; + + case GICD_ISENABLER ... GICD_ISENABLERN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER); + if ( rank == NULL) goto write_ignore; + vgic_lock_rank(v, rank); + tr = rank->ienable; + rank->ienable |= *r; + vgic_unlock_rank(v, rank); + vgic_enable_irqs(v, (*r) & (~tr), gicd_reg - GICD_ISENABLER); + return 1; + + case GICD_ICENABLER ... GICD_ICENABLERN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER); + if ( rank == NULL) goto write_ignore; + vgic_lock_rank(v, rank); + tr = rank->ienable; + rank->ienable &= ~*r; + vgic_unlock_rank(v, rank); + vgic_disable_irqs(v, (*r) & tr, gicd_reg - GICD_ICENABLER); + return 1; + + case GICD_ISPENDR ... GICD_ISPENDRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDR%d\n", + dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ISPENDR); + return 0; + + case GICD_ICPENDR ... GICD_ICPENDRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDR%d\n", + dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ICPENDR); + return 0; + + case GICD_ISACTIVER ... GICD_ISACTIVERN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER); + if ( rank == NULL) goto write_ignore; + vgic_lock_rank(v, rank); + rank->iactive &= ~*r; + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ICACTIVER ... GICD_ICACTIVERN: + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER); + if ( rank == NULL) goto write_ignore; + vgic_lock_rank(v, rank); + rank->iactive &= ~*r; + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ITARGETSR ... GICD_ITARGETSR + 7: + /* SGI/PPI target is read only */ + goto write_ignore; + + case GICD_ITARGETSR + 8 ... GICD_ITARGETSRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR); + if ( rank == NULL) goto write_ignore; + vgic_lock_rank(v, rank); + if ( dabt.size == 2 ) + rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)] = *r; + else + byte_write(&rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)], + *r, offset); + vgic_unlock_rank(v, rank); + return 1; + + case GICD_IPRIORITYR ... GICD_IPRIORITYRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR); + if ( rank == NULL) goto write_ignore; + vgic_lock_rank(v, rank); + if ( dabt.size == 2 ) + rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)] = *r; + else + byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)], + *r, offset); + vgic_unlock_rank(v, rank); + return 1; + + case GICD_ICFGR: /* SGIs */ + goto write_ignore; + case GICD_ICFGR + 1: /* PPIs */ + /* It is implementation defined if these are writeable. We chose not */ + goto write_ignore; + case GICD_ICFGR + 2 ... GICD_ICFGRN: /* SPIs */ + if ( dabt.size != 2 ) goto bad_width; + rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR); + vgic_lock_rank(v, rank); + if ( rank == NULL) goto write_ignore; + rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)] = *r; + vgic_unlock_rank(v, rank); + return 1; + + case GICD_NSACR ... GICD_NSACRN: + /* We do not implement security extensions for guests, write ignore */ + goto write_ignore; + + case GICD_SGIR: + if ( dabt.size != 2 ) + goto bad_width; + return vgic_to_sgi(v, *r); + + case GICD_CPENDSGIR ... GICD_CPENDSGIRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDSGIR%d\n", + dabt.size ? "word" : "byte", *r, gicd_reg - GICD_CPENDSGIR); + return 0; + + case GICD_SPENDSGIR ... GICD_SPENDSGIRN: + if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; + printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDSGIR%d\n", + dabt.size ? "word" : "byte", *r, gicd_reg - GICD_SPENDSGIR); + return 0; + + /* Implementation defined -- write ignored */ + case REG(0xfd0) ... REG(0xfe4): + goto write_ignore; + + /* R/O -- write ignore */ + case GICD_ICPIDR2: + goto write_ignore; + + /* Implementation defined -- write ignored */ + case REG(0xfec) ... REG(0xffc): + goto write_ignore; + + /* Reserved -- write ignored */ + case REG(0x00c) ... REG(0x01c): + case REG(0x040) ... REG(0x07c): + case REG(0x7fc): + case REG(0xbfc): + case REG(0xf04) ... REG(0xf0c): + case REG(0xf30) ... REG(0xfcc): + goto write_ignore; + + default: + printk("vGICD: unhandled write r%d=%"PRIregister" offset %#08x\n", + dabt.reg, *r, offset); + return 0; + } + +bad_width: + printk("vGICD: bad write width %d r%d=%"PRIregister" offset %#08x\n", + dabt.size, dabt.reg, *r, offset); + domain_crash_synchronous(); + return 0; + +write_ignore: + if ( dabt.size != 2 ) goto bad_width; + return 1; +} + +static int vgic_distr_mmio_check(struct vcpu *v, paddr_t addr) +{ + struct domain *d = v->domain; + + return (addr >= (d->arch.vgic.dbase)) && (addr < (d->arch.vgic.dbase + PAGE_SIZE)); +} + +static struct mmio_handler vgic_distr_mmio_handler = { + .check_handler = vgic_distr_mmio_check, + .read_handler = vgic_distr_mmio_read, + .write_handler = vgic_distr_mmio_write, +}; + +int vgic_v2_init(struct domain *d) +{ + int i; + struct vgic_irq_rank *r; + + d->arch.vgic.shared_irqs = + (struct vgic_irq_rank *)xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d)); + + for (i=0; iarch.vgic.shared_irqs) + + sizeof(struct vgic_irq_rank) * i); + spin_lock_init(&r->lock); + } + register_vgic_ops(&ops); + + register_mmio_handler(&vgic_distr_mmio_handler); + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 9c907b5..b60f012 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -31,57 +31,53 @@ #include #include -#define REG(n) (n/4) -/* Number of ranks of interrupt registers for a domain */ -#define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32) +static struct vgic_ops *vgic_ops; -/* Represents state corresponding to a block of 32 interrupts */ -struct vgic_irq_rank { - spinlock_t lock; /* Covers access to all other members of this struct */ - uint32_t ienable, iactive, ipend, pendsgi; - uint32_t icfg[2]; - uint32_t ipriority[8]; - uint32_t itargets[8]; -}; - -/* - * Rank containing GICD_ for GICD_ with - * -bits-per-interrupt - */ -static inline int REG_RANK_NR(int b, uint32_t n) +void register_vgic_ops(struct vgic_ops *ops) { - switch ( b ) - { - case 8: return n >> 3; - case 4: return n >> 2; - case 2: return n >> 1; - case 1: return n; - default: BUG(); - } + vgic_ops = ops; } -/* - * Offset of GICD_ with its rank, for GICD_ with - * -bits-per-interrupt. - */ -#define REG_RANK_INDEX(b, n) ((n) & ((b)-1)) - -/* - * Returns rank corresponding to a GICD_ register for - * GICD_ with -bits-per-interrupt. - */ -static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n) +int domain_vgic_init(struct domain *d) { - int rank = REG_RANK_NR(b, n); + int i; + + static const struct dt_device_match gicv2_ids[] __initconst = + { + DT_MATCH_GIC, + { /* sentinel */ }, + }; + struct dt_device_node *node; + + d->arch.vgic.ctlr = 0; - if ( rank == 0 ) - return (struct vgic_irq_rank *)v->arch.vgic.private_irqs; - else if ( rank <= DOMAIN_NR_RANKS(v->domain) ) - return (struct vgic_irq_rank *)((unsigned char *)(v->domain->arch.vgic.shared_irqs) - + (sizeof(struct vgic_irq_rank) *(rank - 1))); + /* 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 - return NULL; + d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */ + + node = dt_find_interrupt_controller(gicv2_ids); + if ( node ) + { + if (vgic_v2_init(d)) + panic("vgic v2 initialization failed"); + goto out; + } + if ( !node ) + panic("Unable to find compatible vGIC"); +out: + d->arch.vgic.pending_irqs = + xzalloc_array(struct pending_irq, d->arch.vgic.nr_lines); + for (i=0; iarch.vgic.nr_lines; i++) + { + INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].inflight); + INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].lr_queue); + } + return 0; } void domain_vgic_free(struct domain *d) @@ -93,11 +89,11 @@ void domain_vgic_free(struct domain *d) int vcpu_vgic_init(struct vcpu *v) { int i; - struct vgic_irq_rank *vir; - vir = xzalloc(struct vgic_irq_rank); - memset(vir, 0, sizeof(struct vgic_irq_rank)); - spin_lock_init(&vir->lock); + if (vgic_ops) + vgic_ops->vgic_vcpu_init(v); + else + panic("No VGIC ops found\n"); memset(&v->arch.vgic.pending_irqs, 0, sizeof(v->arch.vgic.pending_irqs)); for (i = 0; i < 32; i++) @@ -106,16 +102,6 @@ int vcpu_vgic_init(struct vcpu *v) INIT_LIST_HEAD(&v->arch.vgic.pending_irqs[i].lr_queue); } - /* For SGI and PPI the target is always this CPU */ - for ( i = 0 ; i < 8 ; i++ ) - vir->itargets[i] = - (1<<(v->vcpu_id+0)) - | (1<<(v->vcpu_id+8)) - | (1<<(v->vcpu_id+16)) - | (1<<(v->vcpu_id+24)); - - v->arch.vgic.private_irqs = (struct vgic_irq_irank *)vir; - INIT_LIST_HEAD(&v->arch.vgic.inflight_irqs); INIT_LIST_HEAD(&v->arch.vgic.lr_pending); spin_lock_init(&v->arch.vgic.lock); @@ -123,232 +109,7 @@ int vcpu_vgic_init(struct vcpu *v) return 0; } -#define vgic_lock(v) spin_lock_irq(&(v)->domain->arch.vgic.lock) -#define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock) - -#define vgic_lock_rank(v, r) spin_lock(&(r)->lock) -#define vgic_unlock_rank(v, r) spin_unlock(&(r)->lock) - -static uint32_t byte_read(uint32_t val, int sign, int offset) -{ - int byte = offset & 0x3; - - val = val >> (8*byte); - if ( sign && (val & 0x80) ) - val |= 0xffffff00; - else - val &= 0x000000ff; - return val; -} - -static void byte_write(uint32_t *reg, uint32_t var, int offset) -{ - int byte = offset & 0x3; - - var &= (0xff << (8*byte)); - - *reg &= ~(0xff << (8*byte)); - *reg |= var; -} - -static int vgic_distr_mmio_read(struct vcpu *v, mmio_info_t *info) -{ - struct hsr_dabt dabt = info->dabt; - struct cpu_user_regs *regs = guest_cpu_user_regs(); - register_t *r = select_user_reg(regs, dabt.reg); - struct vgic_irq_rank *rank; - int offset = (int)(info->gpa - v->domain->arch.vgic.dbase); - int gicd_reg = REG(offset); - - switch ( gicd_reg ) - { - case GICD_CTLR: - if ( dabt.size != 2 ) goto bad_width; - vgic_lock(v); - *r = v->domain->arch.vgic.ctlr; - vgic_unlock(v); - return 1; - case GICD_TYPER: - if ( dabt.size != 2 ) goto bad_width; - /* No secure world support for guests. */ - vgic_lock(v); - *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS ) - |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES ); - vgic_unlock(v); - return 1; - case GICD_IIDR: - if ( dabt.size != 2 ) goto bad_width; - /* - * XXX Do we need a JEP106 manufacturer ID? - * Just use the physical h/w value for now - */ - *r = 0x0000043b; - return 1; - - /* Implementation defined -- read as zero */ - case REG(0x020) ... REG(0x03c): - goto read_as_zero; - - case GICD_IGROUPR ... GICD_IGROUPRN: - /* We do not implement security extensions for guests, read zero */ - goto read_as_zero; - - case GICD_ISENABLER ... GICD_ISENABLERN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = rank->ienable; - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ICENABLER ... GICD_ICENABLERN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = rank->ienable; - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ISPENDR ... GICD_ISPENDRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISPENDR); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = byte_read(rank->ipend, dabt.sign, offset); - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ICPENDR ... GICD_ICPENDRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICPENDR); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = byte_read(rank->ipend, dabt.sign, offset); - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ISACTIVER ... GICD_ISACTIVERN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = rank->iactive; - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ICACTIVER ... GICD_ICACTIVERN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = rank->iactive; - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ITARGETSR ... GICD_ITARGETSRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR); - if ( rank == NULL) goto read_as_zero; - - vgic_lock_rank(v, rank); - *r = rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)]; - if ( dabt.size == 0 ) - *r = byte_read(*r, dabt.sign, offset); - vgic_unlock_rank(v, rank); - return 1; - - case GICD_IPRIORITYR ... GICD_IPRIORITYRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR); - if ( rank == NULL) goto read_as_zero; - - vgic_lock_rank(v, rank); - *r = rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)]; - if ( dabt.size == 0 ) - *r = byte_read(*r, dabt.sign, offset); - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ICFGR ... GICD_ICFGRN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)]; - vgic_unlock_rank(v, rank); - return 1; - - case GICD_NSACR ... GICD_NSACRN: - /* We do not implement security extensions for guests, read zero */ - goto read_as_zero; - - case GICD_SGIR: - if ( dabt.size != 2 ) goto bad_width; - /* Write only -- read unknown */ - *r = 0xdeadbeef; - return 1; - - case GICD_CPENDSGIR ... GICD_CPENDSGIRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_CPENDSGIR); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = byte_read(rank->pendsgi, dabt.sign, offset); - vgic_unlock_rank(v, rank); - return 1; - - case GICD_SPENDSGIR ... GICD_SPENDSGIRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_SPENDSGIR); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank); - *r = byte_read(rank->pendsgi, dabt.sign, offset); - vgic_unlock_rank(v, rank); - return 1; - - /* Implementation defined -- read as zero */ - case REG(0xfd0) ... REG(0xfe4): - goto read_as_zero; - - case GICD_ICPIDR2: - if ( dabt.size != 2 ) goto bad_width; - printk("vGICD: unhandled read from ICPIDR2\n"); - return 0; - - /* Implementation defined -- read as zero */ - case REG(0xfec) ... REG(0xffc): - goto read_as_zero; - - /* Reserved -- read as zero */ - case REG(0x00c) ... REG(0x01c): - case REG(0x040) ... REG(0x07c): - case REG(0x7fc): - case REG(0xbfc): - case REG(0xf04) ... REG(0xf0c): - case REG(0xf30) ... REG(0xfcc): - goto read_as_zero; - - default: - printk("vGICD: unhandled read r%d offset %#08x\n", - dabt.reg, offset); - return 0; - } - -bad_width: - printk("vGICD: bad read width %d r%d offset %#08x\n", - dabt.size, dabt.reg, offset); - domain_crash_synchronous(); - return 0; - -read_as_zero: - if ( dabt.size != 2 ) goto bad_width; - *r = 0; - return 1; -} - -static void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n) +void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n) { const unsigned long mask = r; struct pending_irq *p; @@ -366,7 +127,7 @@ static void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n) } } -static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) +void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) { const unsigned long mask = r; struct pending_irq *p; @@ -382,310 +143,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) if ( p->desc != NULL ) p->desc->handler->enable(p->desc); i++; - } + } } -static inline int is_vcpu_running(struct domain *d, int vcpuid) -{ - struct vcpu *v; - - if ( vcpuid >= d->max_vcpus ) - return 0; - - v = d->vcpu[vcpuid]; - if ( v == NULL ) - return 0; - if (test_bit(_VPF_down, &v->pause_flags) ) - return 0; - - return 1; -} - -static int vgic_to_sgi(struct vcpu *v, register_t sgir) -{ - struct domain *d = v->domain; - int virtual_irq; - int filter; - int vcpuid; - int i; - unsigned long vcpu_mask = 0; - - ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask)); - - filter = (sgir & GICD_SGI_TARGET_LIST_MASK); - virtual_irq = (sgir & GICD_SGI_INTID_MASK); - ASSERT( virtual_irq < 16 ); - - switch ( filter ) - { - case GICD_SGI_TARGET_LIST: - vcpu_mask = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT; - break; - case GICD_SGI_TARGET_OTHERS: - for ( i = 0; i < d->max_vcpus; i++ ) - { - if ( i != current->vcpu_id && is_vcpu_running(d, i) ) - set_bit(i, &vcpu_mask); - } - break; - case GICD_SGI_TARGET_SELF: - set_bit(current->vcpu_id, &vcpu_mask); - break; - default: - gdprintk(XENLOG_WARNING, "vGICD: unhandled GICD_SGIR write %"PRIregister" with wrong TargetListFilter field\n", - sgir); - return 0; - } - - for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus ) - { - if ( !is_vcpu_running(d, vcpuid) ) - { - gdprintk(XENLOG_WARNING, "vGICD: GICD_SGIR write r=%"PRIregister" vcpu_mask=%lx, wrong CPUTargetList\n", - sgir, vcpu_mask); - continue; - } - vgic_vcpu_inject_irq(d->vcpu[vcpuid], virtual_irq, 1); - } - return 1; -} - -static int vgic_distr_mmio_write(struct vcpu *v, mmio_info_t *info) -{ - struct hsr_dabt dabt = info->dabt; - struct cpu_user_regs *regs = guest_cpu_user_regs(); - register_t *r = select_user_reg(regs, dabt.reg); - struct vgic_irq_rank *rank; - int offset = (int)(info->gpa - v->domain->arch.vgic.dbase); - int gicd_reg = REG(offset); - uint32_t tr; - - switch ( gicd_reg ) - { - case GICD_CTLR: - if ( dabt.size != 2 ) goto bad_width; - /* Ignore all but the enable bit */ - v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE; - return 1; - - /* R/O -- write ignored */ - case GICD_TYPER: - case GICD_IIDR: - goto write_ignore; - - /* Implementation defined -- write ignored */ - case REG(0x020) ... REG(0x03c): - goto write_ignore; - - case GICD_IGROUPR ... GICD_IGROUPRN: - /* We do not implement security extensions for guests, write ignore */ - goto write_ignore; - - case GICD_ISENABLER ... GICD_ISENABLERN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER); - if ( rank == NULL) goto write_ignore; - vgic_lock_rank(v, rank); - tr = rank->ienable; - rank->ienable |= *r; - vgic_unlock_rank(v, rank); - vgic_enable_irqs(v, (*r) & (~tr), gicd_reg - GICD_ISENABLER); - return 1; - - case GICD_ICENABLER ... GICD_ICENABLERN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER); - if ( rank == NULL) goto write_ignore; - vgic_lock_rank(v, rank); - tr = rank->ienable; - rank->ienable &= ~*r; - vgic_unlock_rank(v, rank); - vgic_disable_irqs(v, (*r) & tr, gicd_reg - GICD_ICENABLER); - return 1; - - case GICD_ISPENDR ... GICD_ISPENDRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDR%d\n", - dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ISPENDR); - return 0; - - case GICD_ICPENDR ... GICD_ICPENDRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDR%d\n", - dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ICPENDR); - return 0; - - case GICD_ISACTIVER ... GICD_ISACTIVERN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER); - if ( rank == NULL) goto write_ignore; - vgic_lock_rank(v, rank); - rank->iactive &= ~*r; - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ICACTIVER ... GICD_ICACTIVERN: - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER); - if ( rank == NULL) goto write_ignore; - vgic_lock_rank(v, rank); - rank->iactive &= ~*r; - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ITARGETSR ... GICD_ITARGETSR + 7: - /* SGI/PPI target is read only */ - goto write_ignore; - - case GICD_ITARGETSR + 8 ... GICD_ITARGETSRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR); - if ( rank == NULL) goto write_ignore; - vgic_lock_rank(v, rank); - if ( dabt.size == 2 ) - rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)] = *r; - else - byte_write(&rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)], - *r, offset); - vgic_unlock_rank(v, rank); - return 1; - - case GICD_IPRIORITYR ... GICD_IPRIORITYRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR); - if ( rank == NULL) goto write_ignore; - vgic_lock_rank(v, rank); - if ( dabt.size == 2 ) - rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)] = *r; - else - byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)], - *r, offset); - vgic_unlock_rank(v, rank); - return 1; - - case GICD_ICFGR: /* SGIs */ - goto write_ignore; - case GICD_ICFGR + 1: /* PPIs */ - /* It is implementation defined if these are writeable. We chose not */ - goto write_ignore; - case GICD_ICFGR + 2 ... GICD_ICFGRN: /* SPIs */ - if ( dabt.size != 2 ) goto bad_width; - rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR); - vgic_lock_rank(v, rank); - if ( rank == NULL) goto write_ignore; - rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)] = *r; - vgic_unlock_rank(v, rank); - return 1; - - case GICD_NSACR ... GICD_NSACRN: - /* We do not implement security extensions for guests, write ignore */ - goto write_ignore; - - case GICD_SGIR: - if ( dabt.size != 2 ) - goto bad_width; - return vgic_to_sgi(v, *r); - - case GICD_CPENDSGIR ... GICD_CPENDSGIRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDSGIR%d\n", - dabt.size ? "word" : "byte", *r, gicd_reg - GICD_CPENDSGIR); - return 0; - - case GICD_SPENDSGIR ... GICD_SPENDSGIRN: - if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width; - printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDSGIR%d\n", - dabt.size ? "word" : "byte", *r, gicd_reg - GICD_SPENDSGIR); - return 0; - - /* Implementation defined -- write ignored */ - case REG(0xfd0) ... REG(0xfe4): - goto write_ignore; - - /* R/O -- write ignore */ - case GICD_ICPIDR2: - goto write_ignore; - - /* Implementation defined -- write ignored */ - case REG(0xfec) ... REG(0xffc): - goto write_ignore; - - /* Reserved -- write ignored */ - case REG(0x00c) ... REG(0x01c): - case REG(0x040) ... REG(0x07c): - case REG(0x7fc): - case REG(0xbfc): - case REG(0xf04) ... REG(0xf0c): - case REG(0xf30) ... REG(0xfcc): - goto write_ignore; - - default: - printk("vGICD: unhandled write r%d=%"PRIregister" offset %#08x\n", - dabt.reg, *r, offset); - return 0; - } - -bad_width: - printk("vGICD: bad write width %d r%d=%"PRIregister" offset %#08x\n", - dabt.size, dabt.reg, *r, offset); - domain_crash_synchronous(); - return 0; - -write_ignore: - if ( dabt.size != 2 ) goto bad_width; - return 1; -} - -static int vgic_distr_mmio_check(struct vcpu *v, paddr_t addr) -{ - struct domain *d = v->domain; - - return (addr >= (d->arch.vgic.dbase)) && (addr < (d->arch.vgic.dbase + PAGE_SIZE)); -} - -static struct mmio_handler vgic_distr_mmio_handler = { - .check_handler = vgic_distr_mmio_check, - .read_handler = vgic_distr_mmio_read, - .write_handler = vgic_distr_mmio_write, -}; - -int domain_vgic_init(struct domain *d) -{ - int i; - struct vgic_irq_rank *r; - - d->arch.vgic.ctlr = 0; - - /* 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.shared_irqs = - (struct vgic_irq_rank *)xzalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d)); - - d->arch.vgic.pending_irqs = - xzalloc_array(struct pending_irq, d->arch.vgic.nr_lines); - for (i=0; iarch.vgic.nr_lines; i++) - { - INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].inflight); - INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].lr_queue); - } - for (i=0; iarch.vgic.shared_irqs) - + sizeof(struct vgic_irq_rank) * i); - spin_lock_init(&r->lock); - } - - register_mmio_handler(&vgic_distr_mmio_handler); - return 0; -} - - struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq) { struct pending_irq *n; @@ -712,15 +172,13 @@ void vgic_clear_pending_irqs(struct vcpu *v) void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual) { - int idx = irq >> 2, byte = irq & 0x3; uint8_t priority; - struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, idx); - struct pending_irq *iter, *n = irq_to_pending(v, irq); + struct pending_irq *iter; + struct pending_irq *n = irq_to_pending(v, irq); unsigned long flags; bool_t running; spin_lock_irqsave(&v->arch.vgic.lock, flags); - if ( !list_empty(&n->inflight) ) { if ( (irq != current->domain->arch.evtchn_irq) || @@ -737,7 +195,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual) return; } - priority = byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, byte); + priority = vgic_ops->read_priority(v, irq); n->irq = irq; set_bit(GIC_IRQ_GUEST_PENDING, &n->status); diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 4244491..2de6c6a 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -54,6 +54,9 @@ extern void domain_vgic_free(struct domain *d); extern int vcpu_vgic_init(struct vcpu *v); extern int vcpu_gic_init(struct vcpu *v); +extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n); +extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n); +extern int vgic_v2_init(struct domain *d); extern void gicv2_init(void); @@ -130,7 +133,13 @@ struct gic_hw_operations { unsigned long (*read_cpu_sgi_rbase)(void); }; +struct vgic_ops { + int (*vgic_vcpu_init)(struct vcpu *v); + int (*read_priority)(struct vcpu *v, int irq); +}; + extern void register_gic_ops(struct gic_hw_operations *); +extern void register_vgic_ops(struct vgic_ops *ops); extern void update_cpu_lr_mask(void); extern void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi); -- 1.7.9.5