[xen staging] libx86: Introduce a helper to serialise cpuid_policy objects

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[xen staging] libx86: Introduce a helper to serialise cpuid_policy objects

patchbot
commit 43a9573a8ed7c32f019aa7251c26f9be03770a94
Author:     Andrew Cooper <[hidden email]>
AuthorDate: Thu Jun 21 16:35:49 2018 +0200
Commit:     Andrew Cooper <[hidden email]>
CommitDate: Tue Nov 6 17:51:18 2018 +0000

    libx86: Introduce a helper to serialise cpuid_policy objects
   
    The serialised form is made up of the leaf, subleaf and data tuple.  As this
    is the architectural form, it is expected not to change going forwards.
   
    The serialisation of the Xen/Viridian leaves isn't fully implemented yet.  It
    is just enough to be bug-compatible with the current DOMCTL_set_cpuid
    behaviour, but needs further hypervisor work before the toolstack can sensibly
    control these values.
   
    x86_cpuid_copy_to_buffer() is implemented using Xen's regular copy_to_guest
    primitives, with an API-compatible memcpy() is used for the libxc half of the
    build.
   
    Signed-off-by: Andrew Cooper <[hidden email]>
    Signed-off-by: Roger Pau Monné <[hidden email]>
    Signed-off-by: Sergey Dyasli <[hidden email]>
    Reviewed-by: Wei Liu <[hidden email]>
    Reviewed-by: Jan Beulich <[hidden email]>
---
 xen/include/public/arch-x86/xen.h | 11 +++++
 xen/include/xen/lib/x86/cpuid.h   | 36 ++++++++++++++++
 xen/lib/x86/cpuid.c               | 91 +++++++++++++++++++++++++++++++++++++++
 xen/lib/x86/private.h             | 18 ++++++++
 4 files changed, 156 insertions(+)

diff --git a/xen/include/public/arch-x86/xen.h b/xen/include/public/arch-x86/xen.h
index c76622654a..7980f9e584 100644
--- a/xen/include/public/arch-x86/xen.h
+++ b/xen/include/public/arch-x86/xen.h
@@ -314,6 +314,17 @@ struct xen_arch_domainconfig {
 #define XEN_ACPI_GPE0_CPUHP_BIT      2
 #endif
 
+/*
+ * Representations of architectural CPUID information.  Used as the
+ * serialised version of Xen's internal representation.
+ */
+typedef struct xen_cpuid_leaf {
+#define XEN_CPUID_NO_SUBLEAF 0xffffffffu
+    uint32_t leaf, subleaf;
+    uint32_t a, b, c, d;
+} xen_cpuid_leaf_t;
+DEFINE_XEN_GUEST_HANDLE(xen_cpuid_leaf_t);
+
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/xen/include/xen/lib/x86/cpuid.h b/xen/include/xen/lib/x86/cpuid.h
index 93ada23ecb..1e8283ab28 100644
--- a/xen/include/xen/lib/x86/cpuid.h
+++ b/xen/include/xen/lib/x86/cpuid.h
@@ -30,6 +30,19 @@ struct cpuid_leaf
 #define CPUID_GUEST_NR_EXTD       MAX(CPUID_GUEST_NR_EXTD_INTEL, \
                                       CPUID_GUEST_NR_EXTD_AMD)
 
+/*
+ * Maximum number of leaves a struct cpuid_policy turns into when serialised
+ * for interaction with the toolstack.  (Sum of all leaves in each union, less
+ * the entries in basic which sub-unions hang off of.)
+ */
+#define CPUID_MAX_SERIALISED_LEAVES                     \
+    (CPUID_GUEST_NR_BASIC +                             \
+     CPUID_GUEST_NR_FEAT   - !!CPUID_GUEST_NR_FEAT +    \
+     CPUID_GUEST_NR_CACHE  - !!CPUID_GUEST_NR_CACHE +   \
+     CPUID_GUEST_NR_TOPO   - !!CPUID_GUEST_NR_TOPO +    \
+     CPUID_GUEST_NR_XSTATE - !!CPUID_GUEST_NR_XSTATE +  \
+     CPUID_GUEST_NR_EXTD + 2 /* hv_limit and hv2_limit */ )
+
 struct cpuid_policy
 {
 #define DECL_BITFIELD(word) _DECL_BITFIELD(FEATURESET_ ## word)
@@ -230,6 +243,29 @@ static inline void cpuid_featureset_to_policy(
 
 const uint32_t *x86_cpuid_lookup_deep_deps(uint32_t feature);
 
+#ifdef __XEN__
+#include <public/arch-x86/xen.h>
+typedef XEN_GUEST_HANDLE_64(xen_cpuid_leaf_t) cpuid_leaf_buffer_t;
+#else
+#include <xen/arch-x86/xen.h>
+typedef xen_cpuid_leaf_t cpuid_leaf_buffer_t[];
+#endif
+
+/**
+ * Serialise a cpuid_policy object into an array of cpuid leaves.
+ *
+ * @param policy     The cpuid_policy to serialise.
+ * @param leaves     The array of leaves to serialise into.
+ * @param nr_entries The number of entries in 'leaves'.
+ * @returns -errno
+ *
+ * Writes at most CPUID_MAX_SERIALISED_LEAVES.  May fail with -ENOBUFS if the
+ * leaves array is too short.  On success, nr_entries is updated with the
+ * actual number of leaves written.
+ */
+int x86_cpuid_copy_to_buffer(const struct cpuid_policy *policy,
+                             cpuid_leaf_buffer_t leaves, uint32_t *nr_entries);
+
 #endif /* !XEN_LIB_X86_CPUID_H */
 
 /*
diff --git a/xen/lib/x86/cpuid.c b/xen/lib/x86/cpuid.c
index a63e42b166..9b40f55e03 100644
--- a/xen/lib/x86/cpuid.c
+++ b/xen/lib/x86/cpuid.c
@@ -34,6 +34,97 @@ const uint32_t *x86_cpuid_lookup_deep_deps(uint32_t feature)
 }
 
 /*
+ * Copy a single cpuid_leaf into a provided xen_cpuid_leaf_t buffer,
+ * performing boundary checking against the buffer size.
+ */
+static int copy_leaf_to_buffer(uint32_t leaf, uint32_t subleaf,
+                               const struct cpuid_leaf *data,
+                               cpuid_leaf_buffer_t leaves,
+                               uint32_t *curr_entry, const uint32_t nr_entries)
+{
+    const xen_cpuid_leaf_t val = {
+        leaf, subleaf, data->a, data->b, data->c, data->d,
+    };
+
+    if ( *curr_entry == nr_entries )
+        return -ENOBUFS;
+
+    if ( copy_to_buffer_offset(leaves, *curr_entry, &val, 1) )
+        return -EFAULT;
+
+    ++*curr_entry;
+
+    return 0;
+}
+
+int x86_cpuid_copy_to_buffer(const struct cpuid_policy *p,
+                             cpuid_leaf_buffer_t leaves, uint32_t *nr_entries_p)
+{
+    const uint32_t nr_entries = *nr_entries_p;
+    uint32_t curr_entry = 0, leaf, subleaf;
+
+#define COPY_LEAF(l, s, data)                                       \
+    ({                                                              \
+        int ret;                                                    \
+                                                                    \
+        if ( (ret = copy_leaf_to_buffer(                            \
+                  l, s, data, leaves, &curr_entry, nr_entries)) )   \
+            return ret;                                             \
+    })
+
+    /* Basic leaves. */
+    for ( leaf = 0; leaf <= MIN(p->basic.max_leaf,
+                                ARRAY_SIZE(p->basic.raw) - 1); ++leaf )
+    {
+        switch ( leaf )
+        {
+        case 0x4:
+            for ( subleaf = 0; subleaf < ARRAY_SIZE(p->cache.raw); ++subleaf )
+                COPY_LEAF(leaf, subleaf, &p->cache.raw[subleaf]);
+            break;
+
+        case 0x7:
+            for ( subleaf = 0;
+                  subleaf <= MIN(p->feat.max_subleaf,
+                                 ARRAY_SIZE(p->feat.raw) - 1); ++subleaf )
+                COPY_LEAF(leaf, subleaf, &p->feat.raw[subleaf]);
+            break;
+
+        case 0xb:
+            for ( subleaf = 0; subleaf < ARRAY_SIZE(p->topo.raw); ++subleaf )
+                COPY_LEAF(leaf, subleaf, &p->topo.raw[subleaf]);
+            break;
+
+        case 0xd:
+            for ( subleaf = 0; subleaf < ARRAY_SIZE(p->xstate.raw); ++subleaf )
+                COPY_LEAF(leaf, subleaf, &p->xstate.raw[subleaf]);
+            break;
+
+        default:
+            COPY_LEAF(leaf, XEN_CPUID_NO_SUBLEAF, &p->basic.raw[leaf]);
+            break;
+        }
+    }
+
+    /* TODO: Port Xen and Viridian leaves to the new CPUID infrastructure. */
+    COPY_LEAF(0x40000000, XEN_CPUID_NO_SUBLEAF,
+              &(struct cpuid_leaf){ p->hv_limit });
+    COPY_LEAF(0x40000100, XEN_CPUID_NO_SUBLEAF,
+              &(struct cpuid_leaf){ p->hv2_limit });
+
+    /* Extended leaves. */
+    for ( leaf = 0; leaf <= MIN(p->extd.max_leaf & 0xfffful,
+                                ARRAY_SIZE(p->extd.raw) - 1); ++leaf )
+        COPY_LEAF(0x80000000 | leaf, XEN_CPUID_NO_SUBLEAF, &p->extd.raw[leaf]);
+
+#undef COPY_LEAF
+
+    *nr_entries_p = curr_entry;
+
+    return 0;
+}
+
+/*
  * Local variables:
  * mode: C
  * c-file-style: "BSD"
diff --git a/xen/lib/x86/private.h b/xen/lib/x86/private.h
index 8a7cf57f87..83cb6537ef 100644
--- a/xen/lib/x86/private.h
+++ b/xen/lib/x86/private.h
@@ -8,8 +8,13 @@
 #include <xen/lib.h>
 #include <xen/types.h>
 
+#include <asm/guest_access.h>
+
+#define copy_to_buffer_offset copy_to_guest_offset
+
 #else
 
+#include <errno.h>
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stddef.h>
@@ -23,6 +28,19 @@ static inline bool test_bit(unsigned int bit, const void *vaddr)
     return addr[bit / 8] & (1u << (bit % 8));
 }
 
+/* memcpy(), but with copy_to_guest_offset()'s API. */
+#define copy_to_buffer_offset(dst, index, src, nr)      \
+({                                                      \
+    const typeof(*(src)) *src_ = (src);                 \
+    typeof(*(dst)) *dst_ = (dst);                       \
+    typeof(index) index_ = (index);                     \
+    typeof(nr) nr_ = (nr), i_;                          \
+                                                        \
+    for ( i_ = 0; i_ < nr_; i_++ )                      \
+        dst_[index_ + i_] = src_[i_];                   \
+    0;                                                  \
+})
+
 #endif /* __XEN__ */
 
 #endif /* XEN_LIB_X86_PRIVATE_H */
--
generated by git-patchbot for /home/xen/git/xen.git#staging


_______________________________________________
Xen-changelog mailing list
[hidden email]
https://lists.xenproject.org/xen-changelog