#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)
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 */
/*
return NULL;
}
+/*
+ * 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
#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>
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 */