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

[Xen-changelog] [xen master] x86: fix pinned cache attribute handling



commit 4d66f069d6abacd392f1301714fdfc64dc92917b
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Thu Apr 10 16:07:17 2014 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Apr 10 16:07:17 2014 +0200

    x86: fix pinned cache attribute handling
    
    - 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>
---
 xen/arch/x86/hvm/mtrr.c             |   89 ++++++++++++++++++++++++++++++++---
 xen/arch/x86/mm/shadow/multi.c      |    2 +-
 xen/include/asm-x86/hvm/cacheattr.h |   12 ++---
 xen/include/public/domctl.h         |    1 +
 4 files changed, 88 insertions(+), 16 deletions(-)

diff --git a/xen/arch/x86/hvm/mtrr.c b/xen/arch/x86/hvm/mtrr.c
index 9562726..d494fed 100644
--- 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 *vd, struct vcpu *vs)
     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, unsigned long 
gfn, mfn_t mfn,
     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) &&
diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
index 9dfa345..dc90652 100644
--- 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);
diff --git a/xen/include/asm-x86/hvm/cacheattr.h 
b/xen/include/asm-x86/hvm/cacheattr.h
index 371ce95..ab1ccef 100644
--- 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);
 
 
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index f22fe2e..869ae30 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -555,6 +555,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_ioport_mapping_t);
 #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_* */
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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