[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH v3 11/18] xen/arm: ITS: Add GITS registers emulation
On Mon, 2015-06-22 at 17:31 +0530, vijay.kilari@xxxxxxxxx wrote: > From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> > > Emulate GITS* registers and handle LPI configuration > table update trap. These need to only be exposed to a guest which has been configured with an ITS. For dom0 that means at a minimum it needs to be based on the capabilities of the underlying hardware. The same is true of the next patch adding the GICR registers. For domU it seems there is currently no ITS exposed to them, since there is no toolstack changes here, so the emulation should be configured accordingly. > > Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx> > --- > xen/arch/arm/vgic-v3-its.c | 516 > +++++++++++++++++++++++++++++++++++++++++ > xen/include/asm-arm/gic-its.h | 14 ++ > 2 files changed, 530 insertions(+) > > diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c > index 0671434..fa9dccc 100644 > --- a/xen/arch/arm/vgic-v3-its.c > +++ b/xen/arch/arm/vgic-v3-its.c > @@ -63,6 +63,46 @@ static void dump_cmd(its_cmd_block *cmd) > } > #endif > > +void vgic_its_disable_lpis(struct vcpu *v, uint32_t vlpi) > +{ > + struct pending_irq *p; > + unsigned long flags; > + > + p = irq_to_pending(v, vlpi); > + clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status); > + gic_remove_from_queues(v, vlpi); > + if ( p->desc != NULL ) > + { > + spin_lock_irqsave(&p->desc->lock, flags); > + p->desc->handler->disable(p->desc); > + spin_unlock_irqrestore(&p->desc->lock, flags); > + } > +} > + > +void vgic_its_enable_lpis(struct vcpu *v, uint32_t vlpi, uint8_t priority) > +{ > + struct pending_irq *p; > + unsigned long flags; > + > + /* Get plpi for the given vlpi */ > + p = irq_to_pending(v, vlpi); > + p->priority = priority; > + set_bit(GIC_IRQ_GUEST_ENABLED, &p->status); > + > + spin_lock_irqsave(&v->arch.vgic.lock, flags); > + > + if ( !list_empty(&p->inflight) && > + !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) ) > + gic_raise_guest_irq(v, irq_to_virq(p->desc), p->priority); > + > + spin_unlock_irqrestore(&v->arch.vgic.lock, flags); > + if ( p->desc != NULL ) > + { > + spin_lock_irqsave(&p->desc->lock, flags); > + p->desc->handler->enable(p->desc); > + spin_unlock_irqrestore(&p->desc->lock, flags); > + } > +} > /* ITS device table helper functions */ > int vits_vdevice_entry(struct domain *d, uint32_t dev_id, > struct vdevice_table *entry, int set) > @@ -649,6 +689,482 @@ err: > return 0; > } > > +static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info) > +{ > + uint32_t offset; > + struct hsr_dabt dabt = info->dabt; > + struct cpu_user_regs *regs = guest_cpu_user_regs(); > + register_t *r = select_user_reg(regs, dabt.reg); > + uint8_t cfg; > + > + offset = info->gpa - > + (v->domain->arch.vits->propbase & 0xfffffffff000UL); > + > + if ( offset < SZ_64K ) > + { > + DPRINTK("vITS:d%dv%d LPI Table read offset 0x%x\n", > + v->domain->domain_id, v->vcpu_id, offset); > + cfg = readb_relaxed(v->domain->arch.vits->prop_page + offset); > + *r = cfg; > + return 1; > + } > + else > + dprintk(XENLOG_G_ERR, "vITS:d%dv%d LPI Table read with wrong offset > 0x%x\n", > + v->domain->domain_id, v->vcpu_id, offset); > + > + > + return 0; > +} > + > +static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info) > +{ > + uint32_t offset; > + uint32_t vid; > + uint8_t cfg; > + bool_t enable; > + struct hsr_dabt dabt = info->dabt; > + struct cpu_user_regs *regs = guest_cpu_user_regs(); > + register_t *r = select_user_reg(regs, dabt.reg); > + > + offset = info->gpa - > + (v->domain->arch.vits->propbase & 0xfffffffff000UL); > + > + vid = offset + NR_GIC_LPI; > + if ( offset < SZ_64K ) > + { > + DPRINTK("vITS:d%dv%d LPI Table write offset 0x%x\n", > + v->domain->domain_id, v->vcpu_id, offset); > + cfg = readb_relaxed(v->domain->arch.vits->prop_page + offset); > + enable = (cfg & *r) & 0x1; > + > + if ( !enable ) > + vgic_its_enable_lpis(v, vid, (*r & 0xfc)); > + else > + vgic_its_disable_lpis(v, vid); > + > + /* Update virtual prop page */ > + writeb_relaxed((*r & 0xff), > + v->domain->arch.vits->prop_page + offset); > + > + return 1; > + } > + else > + dprintk(XENLOG_G_ERR, "vITS:d%dv%d LPI Table invalid write @ 0x%x\n", > + v->domain->domain_id, v->vcpu_id, offset); > + > + return 0; > +} > + > +static const struct mmio_handler_ops vgic_gits_lpi_mmio_handler = { > + .read_handler = vgic_v3_gits_lpi_mmio_read, > + .write_handler = vgic_v3_gits_lpi_mmio_write, > +}; > + > +int vgic_its_unmap_lpi_prop(struct vcpu *v) > +{ > + paddr_t maddr; > + uint32_t lpi_size; > + int i; > + > + maddr = v->domain->arch.vits->propbase & 0xfffffffff000UL; > + lpi_size = 1UL << ((v->domain->arch.vits->propbase & 0x1f) + 1); > + > + DPRINTK("vITS:d%dv%d Unmap guest LPI conf table maddr 0x%lx lpi_size > 0x%x\n", > + v->domain->domain_id, v->vcpu_id, maddr, lpi_size); > + > + if ( lpi_size < SZ_64K ) > + { > + dprintk(XENLOG_G_ERR, "vITS:d%dv%d LPI Prop page < 64K\n", > + v->domain->domain_id, v->vcpu_id); > + return 0; > + } > + > + /* XXX: As per 4.8.9 each re-distributor shares a common LPI > configuration table > + * So one set of mmio handlers to manage configuration table is enough > + */ > + for ( i = 0; i < lpi_size / PAGE_SIZE; i++ ) > + guest_physmap_remove_page(v->domain, paddr_to_pfn(maddr), > + gmfn_to_mfn(v->domain, paddr_to_pfn(maddr)), > 0); > + > + /* Register mmio handlers for this region */ > + register_mmio_handler(v->domain, &vgic_gits_lpi_mmio_handler, > + maddr, lpi_size); > + > + /* Allocate Virtual LPI Property table */ > + v->domain->arch.vits->prop_page = > + alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0); > + if ( !v->domain->arch.vits->prop_page ) > + { > + dprintk(XENLOG_G_ERR, "vITS:d%dv%d Failed to allocate LPI Prop > page\n", > + v->domain->domain_id, v->vcpu_id); > + return 0; > + } > + > + memset(v->domain->arch.vits->prop_page, 0xa2, lpi_size); > + > + return 1; > +} > + > +static inline void vits_spin_lock(struct vgic_its *vits) > +{ > + spin_lock(&vits->lock); > +} > + > +static inline void vits_spin_unlock(struct vgic_its *vits) > +{ > + spin_unlock(&vits->lock); > +} > + > +static int vgic_v3_gits_mmio_read(struct vcpu *v, mmio_info_t *info) > +{ > + struct vgic_its *vits; > + struct hsr_dabt dabt = info->dabt; > + struct cpu_user_regs *regs = guest_cpu_user_regs(); > + register_t *r = select_user_reg(regs, dabt.reg); > + uint64_t val = 0; > + uint32_t index, gits_reg; > + > + vits = v->domain->arch.vits; > + > + gits_reg = info->gpa - vits->phys_base; > + > + if ( gits_reg >= SZ_64K ) > + { > + gdprintk(XENLOG_G_WARNING, > + "vITS:d%dv%d unknown gpa read address %"PRIpaddr"\n", > + v->domain->domain_id, v->vcpu_id, info->gpa); > + return 0; > + } > + > + switch ( gits_reg ) > + { > + case GITS_CTLR: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + *r = 0; > + return 1; > + case GITS_IIDR: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + *r = 0; > + return 1; > + case GITS_TYPER: > + vits_spin_lock(vits); > + val = (((v->domain->max_vcpus + 1) << GITS_TYPER_HCC_SHIFT ) | > + VITS_GITS_DEV_BITS | VITS_GITS_ID_BITS | > + VITS_GITS_ITT_SIZE | VITS_GITS_DISTRIBUTED | > + VITS_GITS_PLPIS); > + if ( dabt.size == DABT_DOUBLE_WORD ) > + *r = val; > + else if ( dabt.size == DABT_WORD ) > + *r = (u32)val; > + else > + { > + vits_spin_unlock(vits); > + goto bad_width; > + } > + vits_spin_unlock(vits); > + return 1; > + case GITS_TYPER + 4: > + if (dabt.size != DABT_WORD ) goto bad_width; > + vits_spin_lock(vits); > + val = (((v->domain->max_vcpus + 1) << GITS_TYPER_HCC_SHIFT ) | > + VITS_GITS_DEV_BITS | VITS_GITS_ID_BITS | > + VITS_GITS_ITT_SIZE | VITS_GITS_DISTRIBUTED | > + VITS_GITS_PLPIS); > + *r = (u32)(val >> 32); > + vits_spin_unlock(vits); > + return 1; > + case 0x0010 ... 0x007c: > + case 0xc000 ... 0xffcc: > + /* Implementation defined -- read ignored */ > + dprintk(XENLOG_ERR, > + "vITS:d%dv%d read unknown 0x000c - 0x007c r%d offset > %#08x\n", > + v->domain->domain_id, v->vcpu_id, dabt.reg, gits_reg); > + goto read_as_zero; > + case GITS_CBASER: > + /* XXX: Only read support 32/64-bit access */ > + vits_spin_lock(vits); > + if ( dabt.size == DABT_DOUBLE_WORD ) > + *r = vits->cmd_base && 0xc7ffffffffffffffUL; > + else if ( dabt.size == DABT_WORD ) > + *r = (u32)vits->cmd_base; > + else > + { > + vits_spin_unlock(vits); > + goto bad_width; > + } > + vits_spin_unlock(vits); > + return 1; > + case GITS_CBASER + 4: > + if (dabt.size != DABT_WORD ) > + goto bad_width; > + vits_spin_lock(vits); > + *r = (u32)(vits->cmd_base >> 32); > + vits_spin_unlock(vits); > + return 1; > + case GITS_CWRITER: > + /* XXX: Only read support 32/64-bit access */ > + vits_spin_lock(vits); > + if ( dabt.size == DABT_DOUBLE_WORD ) > + *r = vits->cmd_write; > + else if ( dabt.size == DABT_WORD ) > + *r = (u32)vits->cmd_write; > + else > + { > + vits_spin_unlock(vits); > + goto bad_width; > + } > + vits_spin_unlock(vits); > + return 1; > + case GITS_CWRITER + 4: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + vits_spin_lock(vits); > + *r = (u32)(vits->cmd_write >> 32); > + vits_spin_unlock(vits); > + return 1; > + case GITS_CREADR: > + /* XXX: Only read support 32/64-bit access */ > + vits_spin_lock(vits); > + if ( dabt.size == DABT_DOUBLE_WORD ) > + *r = vits->cmd_read; > + else if ( dabt.size == DABT_WORD ) > + *r = (u32)vits->cmd_read; > + else > + { > + vits_spin_unlock(vits); > + goto bad_width; > + } > + vits_spin_unlock(vits); > + return 1; > + case GITS_CREADR + 4: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + vits_spin_lock(vits); > + *r = (u32)(vits->cmd_read >> 32); > + vits_spin_unlock(vits); > + return 1; > + case 0x0098 ... 0x009c: > + case 0x00a0 ... 0x00fc: > + case 0x0140 ... 0xbffc: > + /* Reserved -- read ignored */ > + dprintk(XENLOG_ERR, > + "vITS:d%dv%d read unknown 0x0098-9c or 0x00a0-fc r%d offset > %#08x\n", > + v->domain->domain_id, v->vcpu_id, dabt.reg, gits_reg); > + goto read_as_zero; > + case GITS_BASER ... GITS_BASERN: > + /* Supports only 64-bit access */ > + if ( dabt.size != DABT_DOUBLE_WORD ) > + goto bad_width; > + if ( (gits_reg % 8) != 0 ) > + goto bad_width; > + vits_spin_lock(vits); > + index = (gits_reg - GITS_BASER) / 8; > + *r = vits->baser[index]; > + vits_spin_unlock(vits); > + return 1; > + case GITS_PIDR0: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + *r = GITS_PIDR0_VAL; > + return 1; > + case GITS_PIDR1: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + *r = GITS_PIDR1_VAL; > + return 1; > + case GITS_PIDR2: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + *r = GITS_PIDR2_VAL; > + return 1; > + case GITS_PIDR3: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + *r = GITS_PIDR3_VAL; > + return 1; > + case GITS_PIDR4: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + *r = GITS_PIDR4_VAL; > + return 1; > + case GITS_PIDR5 ... GITS_PIDR7: > + goto read_as_zero; > + default: > + dprintk(XENLOG_G_ERR, "vITS:d%dv%d unhandled read r%d offset > %#08x\n", > + v->domain->domain_id, v->vcpu_id, dabt.reg, gits_reg); > + return 0; > + } > + > +bad_width: > + dprintk(XENLOG_G_ERR, "vITS:d%dv%d bad read width %d r%d offset %#08x\n", > + v->domain->domain_id, v->vcpu_id, dabt.size, dabt.reg, gits_reg); > + domain_crash_synchronous(); > + return 0; > + > +read_as_zero: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + *r = 0; > + return 1; > +} > + > +#define GITS_BASER_MASK (~((0x7UL << GITS_BASER_TYPE_SHIFT) | \ > + (0xffUL << GITS_BASER_ENTRY_SIZE_SHIFT) | \ > + (0x3UL << GITS_BASER_SHAREABILITY_SHIFT))) > + > +static int vgic_v3_gits_mmio_write(struct vcpu *v, mmio_info_t *info) > +{ > + struct vgic_its *vits; > + struct hsr_dabt dabt = info->dabt; > + struct cpu_user_regs *regs = guest_cpu_user_regs(); > + register_t *r = select_user_reg(regs, dabt.reg); > + int ret; > + uint32_t index, gits_reg, sz, psz; > + uint64_t val; > + > + vits = v->domain->arch.vits; > + > + gits_reg = info->gpa - vits->phys_base; > + > + if ( gits_reg >= SZ_64K ) > + { > + gdprintk(XENLOG_G_WARNING, > + "vITS:d%dv%d unknown gpa write address %"PRIpaddr"\n", > + v->domain->domain_id, v->vcpu_id, info->gpa); > + return 0; > + } > + switch ( gits_reg ) > + { > + case GITS_CTLR: > + if ( dabt.size != DABT_WORD ) > + goto bad_width; > + vits_spin_lock(vits); > + vits->ctrl = *r; > + vits_spin_unlock(vits); > + return 1; > + case GITS_IIDR: > + /* R0 -- write ignored */ > + goto write_ignore; > + case GITS_TYPER: > + case GITS_TYPER + 4: > + /* R0 -- write ignored */ > + goto write_ignore; > + case 0x0010 ... 0x007c: > + case 0xc000 ... 0xffcc: > + /* Implementation defined -- write ignored */ > + dprintk(XENLOG_G_ERR, > + "vITS:d%dv%d write to unknown 0x000c - 0x007c r%d offset > %#08x\n", > + v->domain->domain_id, v->vcpu_id, dabt.reg, gits_reg); > + goto write_ignore; > + case GITS_CBASER: > + if ( dabt.size != DABT_DOUBLE_WORD ) > + goto bad_width; > + vits_spin_lock(vits); > + vits->cmd_base = *r; > + vits->cmd_qsize = SZ_4K * ((*r & 0xff) + 1); > + vits_spin_unlock(vits); > + return 1; > + case GITS_CBASER + 4: > + /* XXX: Does not support word write */ > + goto bad_width; > + case GITS_CWRITER: > + vits_spin_lock(vits); > + if ( dabt.size == DABT_DOUBLE_WORD ) > + vits->cmd_write = *r; > + else if ( dabt.size == DABT_WORD) > + { > + val = vits->cmd_write & 0xffffffff00000000UL; > + val = (*r) | val; > + vits->cmd_write = val; > + } > + else > + { > + vits_spin_unlock(vits); > + goto bad_width; > + } > + ret = vgic_its_process_cmd(v, vits); > + vits_spin_unlock(vits); > + return ret; > + case GITS_CWRITER + 4: > + if (dabt.size != DABT_WORD ) > + goto bad_width; > + vits_spin_lock(vits); > + val = vits->cmd_write & 0xffffffffUL; > + val = ((*r & 0xffffffffUL) << 32) | val; > + vits->cmd_write = val; > + ret = vgic_its_process_cmd(v, vits); > + vits_spin_unlock(vits); > + return ret; > + case GITS_CREADR: > + /* R0 -- write ignored */ > + goto write_ignore; > + case 0x0098 ... 0x009c: > + case 0x00a0 ... 0x00fc: > + case 0x0140 ... 0xbffc: > + /* Reserved -- write ignored */ > + dprintk(XENLOG_G_ERR, > + "vITS:d%dv%d write to unknown 0x98-9c or 0xa0-fc r%d offset > %#08x\n", > + v->domain->domain_id, v->vcpu_id, dabt.reg, gits_reg); > + goto write_ignore; > + case GITS_BASER0: > + if ( dabt.size != DABT_DOUBLE_WORD ) > + goto bad_width; > + vits_spin_lock(vits); > + vits->baser[0] = vits->baser[0] | (GITS_BASER_MASK & *r); > + vits->dt_ipa = vits->baser[0] & 0xfffffffff000UL; > + psz = (vits->baser[0] >> GITS_BASER_PAGE_SIZE_SHIFT) & > + GITS_BASER_PAGE_SIZE_MASK_VAL; > + if ( psz == GITS_BASER_PAGE_SIZE_4K_VAL ) > + sz = 4; > + else if ( psz == GITS_BASER_PAGE_SIZE_16K_VAL ) > + sz = 16; > + else > + sz = 64; > + > + vits->dt_size = (vits->baser[0] & GITS_BASER_PAGES_MASK_VAL) > + * sz * SZ_1K; > + vits_spin_unlock(vits); > + return 1; > + case GITS_BASER1 ... GITS_BASERN: > + /* Nothing to do with this values. Just store and emulate */ > + if ( dabt.size != DABT_DOUBLE_WORD ) > + goto bad_width; > + if ( (gits_reg % 8) != 0 ) > + goto bad_width; > + vits_spin_lock(vits); > + index = (gits_reg - GITS_BASER) / 8; > + vits->baser[index] = *r; > + vits_spin_unlock(vits); > + return 1; > + case GITS_PIDR7 ... GITS_PIDR0: > + /* R0 -- write ignored */ > + goto write_ignore; > + default: > + dprintk(XENLOG_G_ERR, "vITS:d%dv%d unhandled write r%d offset > %#08x\n", > + v->domain->domain_id, v->vcpu_id, dabt.reg, gits_reg); > + return 0; > + } > + > +bad_width: > + dprintk(XENLOG_G_ERR, "vITS:d%dv%d bad write width %d r%d offset > %#08x\n", > + v->domain->domain_id, v->vcpu_id, dabt.size, dabt.reg, gits_reg); > + domain_crash_synchronous(); > + return 0; > + > +write_ignore: > + if ( dabt.size != DABT_WORD ) goto bad_width; > + *r = 0; > + return 1; > +} > + > + > +static const struct mmio_handler_ops vgic_gits_mmio_handler = { > + .read_handler = vgic_v3_gits_mmio_read, > + .write_handler = vgic_v3_gits_mmio_write, > +}; > + > /* > * Local variables: > * mode: C > diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h > index 8f898a6..3271477 100644 > --- a/xen/include/asm-arm/gic-its.h > +++ b/xen/include/asm-arm/gic-its.h > @@ -38,6 +38,8 @@ struct its_collection { > struct vgic_its > { > spinlock_t lock; > + /* Emulation of BASER */ > + paddr_t baser[8]; > /* Command queue base */ > paddr_t cmd_base; > /* Command queue write pointer */ > @@ -48,8 +50,20 @@ struct vgic_its > paddr_t cmd_read; > /* Command queue size */ > unsigned long cmd_qsize; > + /* ITS mmio physical base */ > + paddr_t phys_base; > + /* ITS mmio physical size */ > + unsigned long phys_size; > /* ITS physical node */ > struct its_node *its; > + /* GICR ctrl register */ > + uint32_t ctrl; > + /* LPI propbase */ > + paddr_t propbase; > + /* percpu pendbase */ > + paddr_t pendbase[MAX_VIRT_CPUS]; > + /* Virtual LPI property table */ > + void * prop_page; > /* vITT device table ipa */ > paddr_t dt_ipa; > /* vITT device table size */ _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |