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

Re: [Xen-devel] [PATCH V4 4/8] xen/arm: Use cpumask_t type for vcpu_mask in vgic_to_sgi



Hi Chen,

On 28/05/15 11:15, Chen Baozi wrote:
> From: Chen Baozi <baozich@xxxxxxxxx>
> 
> Use cpumask_t instead of unsigned long which can only express 64 cpus at
> the most. Add the {gicv2|gicv3}_sgir_to_cpumask in corresponding vGICs
> to translate GICD_SGIR/ICC_SGI1R_EL1 to vcpu_mask for vgic_to_sgi.

This patch does more than using cpumask_t. It's also add AFF1 support
for GICv3. This should at least be mentioned in the patch (and commit
message). But I would prefer a separate patch to add this feature.

Furthermore, cpumask_t is based on NR_CPUS. There is not relation
between NR_CPUS and MAX_VIRT_CPUS so you need to add a BUILD_BUG_ON in
order to catch wrong configuration.

> 
> Signed-off-by: Chen Baozi <baozich@xxxxxxxxx>
> ---
>  xen/arch/arm/vgic-v2.c     | 16 ++++++++++++++--
>  xen/arch/arm/vgic-v3.c     | 19 ++++++++++++++++---
>  xen/arch/arm/vgic.c        | 15 +++++++--------
>  xen/include/asm-arm/vgic.h |  2 +-
>  4 files changed, 38 insertions(+), 14 deletions(-)
> 
> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
> index 3be1a51..2dbe371 100644
> --- a/xen/arch/arm/vgic-v2.c
> +++ b/xen/arch/arm/vgic-v2.c
> @@ -33,6 +33,17 @@
>  #include <asm/gic.h>
>  #include <asm/vgic.h>
>  
> +static void gicv2_sgir_to_cpumask(cpumask_t *cpumask, const register_t sgir)

static inline

> +{
> +    unsigned long target_list;
> +    int cpuid;
> +
> +    target_list = ((sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT);
> +    for_each_set_bit( cpuid, &target_list, 8 )
> +        cpumask_set_cpu(cpuid, cpumask);

The SGI code is called very often by the guest so we need an optimized code.
As there is already a loop later I'd like to avoid another here.

I think the loop can be replaced with:

bitmap_copy(cpumask_bits(cpumask), &target_list, 8);

The operation will be in O(1).

Also please use a define rather than the hardcoded value 8.

> +
> +}
> +
>  static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
>  {
>      struct hsr_dabt dabt = info->dabt;
> @@ -201,11 +212,12 @@ static int vgic_v2_to_sgi(struct vcpu *v, register_t 
> sgir)
>      int virq;
>      int irqmode;
>      enum gic_sgi_mode sgi_mode;
> -    unsigned long vcpu_mask = 0;
> +    cpumask_t vcpu_mask;
>  
> +    cpumask_clear(&vcpu_mask);
>      irqmode = (sgir & GICD_SGI_TARGET_LIST_MASK) >> 
> GICD_SGI_TARGET_LIST_SHIFT;
>      virq = (sgir & GICD_SGI_INTID_MASK);
> -    vcpu_mask = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT;
> +    gicv2_sgir_to_cpumask(&vcpu_mask, sgir);

This is only necessary to call when the SGI target a list of VCPUs
(GICD_SGI_TARGET_LIST_VAL).

>  
>      /* Map GIC sgi value to enum value */
>      switch ( irqmode )
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> index ef9a71a..0da031c 100644
> --- a/xen/arch/arm/vgic-v3.c
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -972,17 +972,30 @@ write_ignore:
>      return 1;
>  }
>  
> +static void gicv3_sgir_to_cpumask(cpumask_t *cpumask, const register_t sgir)
> +{
> +    int target, cpuid;
> +    unsigned long target_mask = sgir & ICH_SGI_TARGETLIST_MASK;
> +
> +    for_each_set_bit( target, &target_mask, 16 )
> +    {
> +        /* XXX: We assume that only AFF1 is used in ICC_SGI1R_EL1. */
> +        cpuid = target + ((sgir >> 16) & 0xff) * 16;

Please use define rather than constant.

> +        cpumask_set_cpu(cpuid, cpumask);
> +    }

Same remark as above, the loop can be avoided.

Furthermore you need to validate the AFF1. A malicious guest can decide
to pass AFF1 >= 16 which will give a CPU higher than 128 and potentially
allow the guest to do a stack overflow in Xen.

> +}
> +
>  static int vgic_v3_to_sgi(struct vcpu *v, register_t sgir)
>  {
>      int virq;
>      int irqmode;
>      enum gic_sgi_mode sgi_mode;
> -    unsigned long vcpu_mask = 0;
> +    cpumask_t vcpu_mask;
>  
> +    cpumask_clear(&vcpu_mask);
>      irqmode = (sgir >> ICH_SGI_IRQMODE_SHIFT) & ICH_SGI_IRQMODE_MASK;
>      virq = (sgir >> ICH_SGI_IRQ_SHIFT ) & ICH_SGI_IRQ_MASK;
> -    /* SGI's are injected at Rdist level 0. ignoring affinity 1, 2, 3 */
> -    vcpu_mask = sgir & ICH_SGI_TARGETLIST_MASK;
> +    gicv3_sgir_to_cpumask(&vcpu_mask, sgir);

It's only necessary when the SGI targets a list of VCPU
(ICH_SGI_TARGET_LIST).

>  
>      /* Map GIC sgi value to enum value */
>      switch ( irqmode )
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 7b387b7..4bf8486 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -318,9 +318,8 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
>      }
>  }
>  
> -/* TODO: unsigned long is used to fit vcpu_mask.*/
>  int vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode, 
> int virq,
> -                unsigned long vcpu_mask)
> +                cpumask_t vcpu_mask)

You need to pass a pointer here, otherwise you will copy all the
cpumask_t everytime which is very expensive.

>  {
>      struct domain *d = v->domain;
>      int vcpuid;

The BUG_ON below can be removed. Keeping here is a call to a potential
unwanted crash of Xen by the guest.

> @@ -341,12 +340,12 @@ int vgic_to_sgi(struct vcpu *v, register_t sgir, enum 
> gic_sgi_mode irqmode, int

>          break;
>      case SGI_TARGET_SELF:
> @@ -355,8 +354,8 @@ int vgic_to_sgi(struct vcpu *v, register_t sgir, enum 
> gic_sgi_mode irqmode, int
>           * SGI_TARGET_SELF mode. So Force vcpu_mask to 0
>           */
>          perfc_incr(vgic_sgi_self);
> -        vcpu_mask = 0;
> -        set_bit(current->vcpu_id, &vcpu_mask);
> +        cpumask_clear(&vcpu_mask);
> +        cpumask_set_cpu(current->vcpu_id, &vcpu_mask);
>          break;
>      default:
>          gprintk(XENLOG_WARNING,
> @@ -365,12 +364,12 @@ int vgic_to_sgi(struct vcpu *v, register_t sgir, enum 
> gic_sgi_mode irqmode, int
>          return 0;
>      }
>  
> -    for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus )
> +    for_each_cpu( vcpuid, &vcpu_mask )

Is there any potential performance impact? You are moving from a loop of
d->max_vcpus to 128 (and potentially more).

>      {
>          if ( d->vcpu[vcpuid] != NULL && !is_vcpu_online(d->vcpu[vcpuid]) )
>          {
>              gprintk(XENLOG_WARNING, "VGIC: write r=%"PRIregister" \
> -                    vcpu_mask=%lx, wrong CPUTargetList\n", sgir, vcpu_mask);
> +                    , wrong CPUTargetList\n", sgir);
>              continue;
>          }

Regards,

-- 
Julien Grall

_______________________________________________
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®.