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

Re: [Xen-devel] [PATCH v3 4/5] x86/HVM: fix pinned cache attribute handling



> From: Jan Beulich [mailto:JBeulich@xxxxxxxx]
> Sent: Monday, April 07, 2014 6:10 PM
> 
> - make sure UC- is only used for PAT purposes (MTRRs and hence EPT
>   don't have this type)
> - add order input to "get", and properly handle conflict case (forcing
>   an EPT page split)
> - properly detect (and refuse) overlaps during "set"
> - properly use RCU constructs
> - support deleting ranges through a special type input to "set"
> - set ignore-PAT flag in epte_get_entry_emt() when "get" succeeds
> - set "get" output to ~0 (invalid) rather than 0 (UC) on error (the
>   caller shouldn't be looking at it anyway)
> - move struct hvm_mem_pinned_cacheattr_range from header to C file
>   (used only there)
> 
> Note that the code (before and after this change) implies the GFN
> ranges passed to the hypercall to be inclusive, which is in contrast
> to the sole current user in qemu (all variants). It is not clear to me
> at which layer (qemu, libxc, hypervisor) this would best be fixed.
> 
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> Reviewed-by: Tim Deegan <tim@xxxxxxx>

Acked-by: Kevin Tian <kevin.tian@xxxxxxxxx>

> 
> --- a/xen/arch/x86/hvm/mtrr.c
> +++ b/xen/arch/x86/hvm/mtrr.c
> @@ -551,6 +551,15 @@ bool_t mtrr_pat_not_equal(struct vcpu *v
>      return 0;
>  }
> 
> +struct hvm_mem_pinned_cacheattr_range {
> +    struct list_head list;
> +    uint64_t start, end;
> +    uint32_t type;
> +    struct rcu_head rcu;
> +};
> +
> +static DEFINE_RCU_READ_LOCK(pinned_cacheattr_rcu_lock);
> +
>  void hvm_init_cacheattr_region_list(
>      struct domain *d)
>  {
> @@ -573,30 +582,47 @@ void hvm_destroy_cacheattr_region_list(
>      }
>  }
> 
> -int32_t hvm_get_mem_pinned_cacheattr(
> +int hvm_get_mem_pinned_cacheattr(
>      struct domain *d,
>      uint64_t guest_fn,
> +    unsigned int order,
>      uint32_t *type)
>  {
>      struct hvm_mem_pinned_cacheattr_range *range;
> +    int rc = 0;
> 
> -    *type = 0;
> +    *type = ~0;
> 
>      if ( !is_hvm_domain(d) )
>          return 0;
> 
> +    rcu_read_lock(&pinned_cacheattr_rcu_lock);
>      list_for_each_entry_rcu ( range,
> 
> &d->arch.hvm_domain.pinned_cacheattr_ranges,
>                                list )
>      {
> -        if ( (guest_fn >= range->start) && (guest_fn <= range->end) )
> +        if ( (guest_fn >= range->start) &&
> +             (guest_fn + (1UL << order) - 1 <= range->end) )
>          {
>              *type = range->type;
> -            return 1;
> +            rc = 1;
> +            break;
> +        }
> +        if ( (guest_fn <= range->end) &&
> +             (range->start <= guest_fn + (1UL << order) - 1) )
> +        {
> +            rc = -1;
> +            break;
>          }
>      }
> +    rcu_read_unlock(&pinned_cacheattr_rcu_lock);
> 
> -    return 0;
> +    return rc;
> +}
> +
> +static void free_pinned_cacheattr_entry(struct rcu_head *rcu)
> +{
> +    xfree(container_of(rcu, struct hvm_mem_pinned_cacheattr_range,
> rcu));
>  }
> 
>  int32_t hvm_set_mem_pinned_cacheattr(
> @@ -606,6 +632,28 @@ int32_t hvm_set_mem_pinned_cacheattr(
>      uint32_t  type)
>  {
>      struct hvm_mem_pinned_cacheattr_range *range;
> +    int rc = 1;
> +
> +    if ( !is_hvm_domain(d) || gfn_end < gfn_start )
> +        return 0;
> +
> +    if ( type == XEN_DOMCTL_DELETE_MEM_CACHEATTR )
> +    {
> +        /* Remove the requested range. */
> +        rcu_read_lock(&pinned_cacheattr_rcu_lock);
> +        list_for_each_entry_rcu ( range,
> +
> &d->arch.hvm_domain.pinned_cacheattr_ranges,
> +                                  list )
> +            if ( range->start == gfn_start && range->end == gfn_end )
> +            {
> +                rcu_read_unlock(&pinned_cacheattr_rcu_lock);
> +                list_del_rcu(&range->list);
> +                call_rcu(&range->rcu, free_pinned_cacheattr_entry);
> +                return 0;
> +            }
> +        rcu_read_unlock(&pinned_cacheattr_rcu_lock);
> +        return -ENOENT;
> +    }
> 
>      if ( !((type == PAT_TYPE_UNCACHABLE) ||
>             (type == PAT_TYPE_WRCOMB) ||
> @@ -616,6 +664,27 @@ int32_t hvm_set_mem_pinned_cacheattr(
>           !is_hvm_domain(d) )
>          return -EINVAL;
> 
> +    rcu_read_lock(&pinned_cacheattr_rcu_lock);
> +    list_for_each_entry_rcu ( range,
> +
> &d->arch.hvm_domain.pinned_cacheattr_ranges,
> +                              list )
> +    {
> +        if ( range->start == gfn_start && range->end == gfn_end )
> +        {
> +            range->type = type;
> +            rc = 0;
> +            break;
> +        }
> +        if ( range->start <= gfn_end && gfn_start <= range->end )
> +        {
> +            rc = -EBUSY;
> +            break;
> +        }
> +    }
> +    rcu_read_unlock(&pinned_cacheattr_rcu_lock);
> +    if ( rc <= 0 )
> +        return rc;
> +
>      range = xzalloc(struct hvm_mem_pinned_cacheattr_range);
>      if ( range == NULL )
>          return -ENOMEM;
> @@ -732,8 +801,14 @@ int epte_get_entry_emt(struct domain *d,
>      if ( !mfn_valid(mfn_x(mfn)) )
>          return MTRR_TYPE_UNCACHABLE;
> 
> -    if ( hvm_get_mem_pinned_cacheattr(d, gfn, &type) )
> -        return type;
> +    switch ( hvm_get_mem_pinned_cacheattr(d, gfn, order, &type) )
> +    {
> +    case 1:
> +        *ipat = 1;
> +        return type != PAT_TYPE_UC_MINUS ? type :
> PAT_TYPE_UNCACHABLE;
> +    case -1:
> +        return -1;
> +    }
> 
>      if ( !iommu_enabled ||
>           (rangeset_is_empty(d->iomem_caps) &&
> --- a/xen/arch/x86/mm/shadow/multi.c
> +++ b/xen/arch/x86/mm/shadow/multi.c
> @@ -601,7 +601,7 @@ _sh_propagate(struct vcpu *v,
>           * 3) if disables snoop control, compute the PAT index with
>           *    gMTRR and gPAT.
>           */
> -        if ( hvm_get_mem_pinned_cacheattr(d, gfn_x(target_gfn), &type) )
> +        if ( hvm_get_mem_pinned_cacheattr(d, gfn_x(target_gfn), 0,
> &type) )
>              sflags |= pat_type_2_pte_flags(type);
>          else if ( d->arch.hvm_domain.is_in_uc_mode )
>              sflags |= pat_type_2_pte_flags(PAT_TYPE_UNCACHABLE);
> --- a/xen/include/asm-x86/hvm/cacheattr.h
> +++ b/xen/include/asm-x86/hvm/cacheattr.h
> @@ -1,12 +1,6 @@
>  #ifndef __HVM_CACHEATTR_H__
>  #define __HVM_CACHEATTR_H__
> 
> -struct hvm_mem_pinned_cacheattr_range {
> -    struct list_head list;
> -    uint64_t start, end;
> -    uint32_t type;
> -};
> -
>  void hvm_init_cacheattr_region_list(
>      struct domain *d);
>  void hvm_destroy_cacheattr_region_list(
> @@ -15,11 +9,13 @@ void hvm_destroy_cacheattr_region_list(
>  /*
>   * To see guest_fn is in the pinned range or not,
>   * if yes, return 1, and set type to value in this range
> - * if no,  return 0, and set type to 0
> + * if no,  return 0, setting type to ~0
> + * if ambiguous, return -1, setting type to ~0 (possible only for order > 0)
>   */
> -int32_t hvm_get_mem_pinned_cacheattr(
> +int hvm_get_mem_pinned_cacheattr(
>      struct domain *d,
>      uint64_t guest_fn,
> +    unsigned int order,
>      uint32_t *type);
> 
> 
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -555,6 +555,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_iopor
>  #define XEN_DOMCTL_MEM_CACHEATTR_WP  5
>  #define XEN_DOMCTL_MEM_CACHEATTR_WB  6
>  #define XEN_DOMCTL_MEM_CACHEATTR_UCM 7
> +#define XEN_DOMCTL_DELETE_MEM_CACHEATTR (~(uint32_t)0)
>  struct xen_domctl_pin_mem_cacheattr {
>      uint64_aligned_t start, end;
>      uint32_t type; /* XEN_DOMCTL_MEM_CACHEATTR_* */
> 


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