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

Re: [Xen-devel] [RFC PATCH 12/19] xen/arm: its: Add support to emulate GICR register for LPIs



On Mon, 2 Mar 2015, vijay.kilari@xxxxxxxxx wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
> 
> With this patch add emulation of GICR registers for LPIs.
> Also add LPI property table emulation.
> 
> Domain's LPI property table is unmapped during domain init
> on LPIPROPBASE update and trapped on LPI property
> table read and write
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
> ---
>  xen/arch/arm/vgic-v3-its.c        |  156 
> +++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic-v3.c            |   64 ++++++++++++---
>  xen/include/asm-arm/domain.h      |    1 +
>  xen/include/asm-arm/gic-its.h     |    1 +
>  xen/include/asm-arm/gic.h         |    2 +
>  xen/include/asm-arm/gic_v3_defs.h |    2 +
>  6 files changed, 214 insertions(+), 12 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
> index 7e1cc04..48c880a 100644
> --- a/xen/arch/arm/vgic-v3-its.c
> +++ b/xen/arch/arm/vgic-v3-its.c
> @@ -996,6 +996,162 @@ err:
>      return 0;
>  }
>  
> +/* Search device structure and get corresponding plpi */
> +int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid)
> +{
> +    struct domain *d = v->domain;
> +    struct vits_device *dev;
> +    struct its_lpi_chunk *chunk;
> +    int i;
> +
> +    list_for_each_entry( dev, &d->arch.vits->vits_dev_list, entry )
> +    {
> +        list_for_each_entry( chunk, &dev->hwirq_list, entry )
> +        {
> +            for ( i = 0; i < IRQS_PER_CHUNK; i++ )
> +            {
> +                if ( test_bit(i, &chunk->lpi_map) && chunk->vid[i] == vid )
> +                {
> +                    *pid = chunk->pid[i];
> +                     return 0;
> +                }
> +            }
> +        }
> +    }
> +
> +    return 1;
> +}
> +
> +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;
> +
> +    spin_lock(&v->domain->arch.vits->lock);
> +    offset = info->gpa -
> +             (v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL);
> +
> +    if ( offset < SZ_64K )
> +    {
> +        DPRINTK("vITS: LPI Table read offset 0x%x\n", offset );
> +        cfg = readb_relaxed(v->domain->arch.vits->lpi_prop_page + offset);
> +        *r = cfg;
> +        spin_unlock(&v->domain->arch.vits->lock);
> +        return 1;
> +    }
> +    else
> +        dprintk(XENLOG_ERR, "vITS: LPI Table read with wrong offset 0x%x\n",
> +                offset);
> +
> +    spin_unlock(&v->domain->arch.vits->lock);
> +
> +    return 0;
> +}
> +
> +static int vgic_v3_gits_lpi_mmio_write(struct vcpu *v, mmio_info_t *info)
> +{
> +    uint32_t offset;
> +    uint32_t pid, 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);
> +
> +    spin_lock(&v->domain->arch.vits->lock);
> +    offset = info->gpa -
> +             (v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL);
> +
> +    vid = offset + NR_GIC_LPI;
> +    if ( offset < SZ_64K )
> +    {
> +        DPRINTK("vITS: LPI Table write offset 0x%x\n", offset );
> +        if ( vgic_its_get_pid(v, vid, &pid) )
> +        {
> +            spin_unlock(&v->domain->arch.vits->lock);
> +            dprintk(XENLOG_ERR, "vITS: pID not found for vid %d\n", vid);
> +            return 0;
> +        }
> +
> +        cfg = readb_relaxed(v->domain->arch.vits->lpi_prop_page + offset);
> +        enable = (cfg & *r) & 0x1;
> +
> +        if ( !enable )
> +             vgic_its_enable_lpis(v, pid);
> +        else
> +             vgic_its_disable_lpis(v, pid);
> +
> +        /* Update virtual prop page */
> +        writeb_relaxed((*r & 0xff),
> +                        v->domain->arch.vits->lpi_prop_page + offset);

We need to properly support priorities too.


> +        spin_unlock(&v->domain->arch.vits->lock);
> +        return 1;
> +    }
> +    else
> +        dprintk(XENLOG_ERR, "vITS: LPI Table write with wrong offset 0x%x\n",
> +                offset);
> +
> +    spin_unlock(&v->domain->arch.vits->lock);
> +
> +    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;
> +
> +    spin_lock(&v->domain->arch.vits->lock);
> +    maddr = v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL;
> +    lpi_size = 1UL << ((v->domain->arch.vits->lpi_propbase & 0x1f) + 1);
> +
> +    DPRINTK("vITS: Unmap guest LPI conf table maddr 0x%lx lpi_size 0x%x\n",
> +             maddr, lpi_size);
> +
> +    if ( lpi_size < SZ_64K )
> +    {
> +        spin_unlock(&v->domain->arch.vits->lock);
> +        dprintk(XENLOG_ERR, "vITS: LPI Prop page < 64K\n");
> +        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->lpi_prop_page =
> +        alloc_xenheap_pages(get_order_from_bytes(lpi_size), 0);

I guess we could reuse the original unmapped guest page instead of allocating a 
new one?


> +    if ( !v->domain->arch.vits->lpi_prop_page )
> +    {
> +        spin_unlock(&v->domain->arch.vits->lock);
> +        dprintk(XENLOG_ERR, "vITS: Failed to allocate LPI Prop page\n");
> +        return 0;
> +    }
> +
> +    memset(v->domain->arch.vits->lpi_prop_page, 0xa2, lpi_size);
> +    spin_unlock(&v->domain->arch.vits->lock);
> +
> +    return 1;
> +}
> +
>  static int __vgic_v3_its_ctrl_mmio_read(struct vcpu *v, mmio_info_t *info,
>                                          uint32_t gits_reg)
>  {
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> index bece189..89e6195 100644
> --- a/xen/arch/arm/vgic-v3.c
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -32,6 +32,7 @@
>  #include <asm/gic_v3_defs.h>
>  #include <asm/gic.h>
>  #include <asm/vgic.h>
> +#include <asm/gic-its.h>
>  
>  /* GICD_PIDRn register values for ARM implementations */
>  #define GICV3_GICD_PIDR0  0x92
> @@ -94,19 +95,29 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, 
> mmio_info_t *info,
>      switch ( gicr_reg )
>      {
>      case GICR_CTLR:
> -        /* We have not implemented LPI's, read zero */
> -        goto read_as_zero;
> +        /*
> +         * Enable LPI's for ITS. Direct injection of LPI
> +         * by writing to GICR_{SET,CLR}LPIR are not supported
> +         */

Is this actually a limitation that we can have? Is there a way to
communicate to the guest OS that GICR_{SET,CLR}LPIR are not supported?


> +        if ( dabt.size != DABT_WORD ) goto bad_width;
> +        vgic_lock(v);
> +        *r = v->domain->arch.vgic.gicr_ctlr;
> +        vgic_unlock(v);
> +        return 1;
>      case GICR_IIDR:
>          if ( dabt.size != DABT_WORD ) goto bad_width;
>          *r = GICV3_GICR_IIDR_VAL;
>          return 1;
>      case GICR_TYPER:
> -        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> -        /* TBD: Update processor id in [23:8] when ITS support is added */
> +        if ( dabt.size != DABT_WORD && dabt.size != DABT_DOUBLE_WORD )
> +            goto bad_width;
> +        /* XXX: Update processor id in [23:8] if GITS_TYPER: PTA is not set 
> */
>          aff = (MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 3) << 56 |
>                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 48 |
>                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 40 |
>                 MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0) << 32);
> +        /* Set LPI support */
> +        aff |= (GICR_TYPER_DISTRIBUTED_IMP | GICR_TYPER_PLPIS);
>          *r = aff;
>          return 1;
>      case GICR_STATUSR:
> @@ -122,10 +133,13 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu 
> *v, mmio_info_t *info,
>          /* WO. Read as zero */
>          goto read_as_zero_64;
>      case GICR_PROPBASER:
> -        /* LPI's not implemented */
> -        goto read_as_zero_64;
> +        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> +        /* Remove shareability attribute we don't want dom to flush */
> +        *r = v->domain->arch.vits->lpi_propbase;
> +        return 1;
>      case GICR_PENDBASER:
> -        /* LPI's not implemented */
> +        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> +        *r = v->domain->arch.vits->lpi_pendbase[v->vcpu_id];
>          goto read_as_zero_64;
>      case GICR_INVLPIR:
>          /* WO. Read as zero */
> @@ -200,8 +214,15 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu 
> *v, mmio_info_t *info,
>      switch ( gicr_reg )
>      {
>      case GICR_CTLR:
> -        /* LPI's not implemented */
> -        goto write_ignore;
> +        /*
> +         * Enable LPI's for ITS. Direct injection of LPI
> +         * by writing to GICR_{SET,CLR}LPIR are not supported
> +         */
> +        if ( dabt.size != DABT_WORD ) goto bad_width;
> +        vgic_lock(v);
> +        v->domain->arch.vgic.gicr_ctlr = (*r) & GICR_CTL_ENABLE;
> +        vgic_unlock(v);
> +        return 1;
>      case GICR_IIDR:
>          /* RO */
>          goto write_ignore;
> @@ -221,11 +242,29 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu 
> *v, mmio_info_t *info,
>          /* LPI is not implemented */
>          goto write_ignore_64;
>      case GICR_PROPBASER:
> +        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> +        vgic_lock(v);
> +        /* LPI configuration tables are shared across cpus. Should be same */
> +        if ( (v->domain->arch.vits->lpi_propbase != 0) &&
> +             ((v->domain->arch.vits->lpi_propbase & 0xfffffffff000UL) !=  
> (*r & 0xfffffffff000UL)) )
> +        {
> +            dprintk(XENLOG_G_ERR,
> +                "vGICv3: vITS: Wrong configuration of LPI_PROPBASER\n");
> +            vgic_unlock(v);
> +            return 0;
> +        }
> +        v->domain->arch.vits->lpi_propbase = *r;
> +        vgic_unlock(v);
> +        return vgic_its_unmap_lpi_prop(v);
>          /* LPI is not implemented */
>          goto write_ignore_64;
>      case GICR_PENDBASER:
> -        /* LPI is not implemented */
> -        goto write_ignore_64;
> +        /* Just hold pendbaser value for guest read */
> +        if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> +        vgic_lock(v);
> +        v->domain->arch.vits->lpi_pendbase[v->vcpu_id] = *r;
> +        vgic_unlock(v);

If I am not mistaken, nothing updates the virtual LPI pending table with
the status of inflight virtual LPIs.  The pending table is not emulated
at all. I think that at the very least you should add a comment saying
that reading the pending status of LPIs via the pending table is not
supported.


> +        return 1;
>      case GICR_INVLPIR:
>          /* LPI is not implemented */
>          goto write_ignore_64;
> @@ -682,7 +721,8 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, 
> mmio_info_t *info)
>          if ( dabt.size != DABT_WORD ) goto bad_width;
>          /* No secure world support for guests. */
>          *r = (((v->domain->max_vcpus << 5) & GICD_TYPE_CPUS ) |
> -              ((v->domain->arch.vgic.nr_spis / 32) & GICD_TYPE_LINES));
> +              ((v->domain->arch.vgic.nr_spis / 32) & GICD_TYPE_LINES) |
> +              GICD_TYPE_LPIS | GICD_TYPE_ID_BITS);
>          return 1;
>      case GICD_STATUSR:
>          /*
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index d02c200..b6d85b8 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -101,6 +101,7 @@ struct arch_domain
>          paddr_t cbase; /* CPU base address */
>  #ifdef CONFIG_ARM_64
>          /* GIC V3 addressing */
> +        int gicr_ctlr;
>          paddr_t dbase_size; /* Distributor base size */
>          paddr_t rbase[MAX_RDIST_COUNT];      /* Re-Distributor base address 
> */
>          paddr_t rbase_size[MAX_RDIST_COUNT]; /* Re-Distributor size */
> diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h
> index bb9ac33..5329e9d 100644
> --- a/xen/include/asm-arm/gic-its.h
> +++ b/xen/include/asm-arm/gic-its.h
> @@ -228,6 +228,7 @@ static inline void its_fixup_cmd(struct its_cmd_block 
> *cmd)
>  void vgic_its_enable_lpis(struct vcpu *v, uint32_t lpi);
>  int vgic_its_get_pid(struct vcpu *v, uint32_t vid, uint32_t *pid);
>  int vgic_its_domain_init(struct domain *d);
> +int vgic_its_unmap_lpi_prop(struct vcpu *v);
>  uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid);
>  
>  int its_check_target(uint64_t vta);
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 1b4b7d1..681d75c 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -96,6 +96,8 @@
>  #define GICD_TYPE_LINES 0x01f
>  #define GICD_TYPE_CPUS  0x0e0
>  #define GICD_TYPE_SEC   0x400
> +#define GICD_TYPE_LPIS           (0x1UL << 17)
> +#define GICD_TYPE_ID_BITS        (0x13UL << 19)
>  
>  #define GICC_CTL_ENABLE 0x1
>  #define GICC_CTL_EOI    (0x1 << 9)
> diff --git a/xen/include/asm-arm/gic_v3_defs.h 
> b/xen/include/asm-arm/gic_v3_defs.h
> index 83d75cf..b81f83f 100644
> --- a/xen/include/asm-arm/gic_v3_defs.h
> +++ b/xen/include/asm-arm/gic_v3_defs.h
> @@ -127,9 +127,11 @@
>  #define GICR_PROPBASER_RaWaWb                (7U << 7)
>  #define GICR_PROPBASER_IDBITS_MASK   (0x1f)
>  
> +#define GICR_CTL_ENABLE              (1U << 0)
>  #define GICR_TYPER_PLPIS             (1U << 0)
>  #define GICR_TYPER_VLPIS             (1U << 1)
>  #define GICR_TYPER_LAST              (1U << 4)
> +#define GICR_TYPER_DISTRIBUTED_IMP   (1U << 3)
>  
>  #define DEFAULT_PMR_VALUE            0xff
>  
> -- 
> 1.7.9.5
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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