[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 1/5] 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 <andrew.cooper3@xxxxxxxxxx> Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> Signed-off-by: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx> Reviewed-by: Wei Liu <wei.liu2@xxxxxxxxxx> --- CC: Jan Beulich <JBeulich@xxxxxxxx> CC: Roger Pau Monné <roger.pau@xxxxxxxxxx> CC: Sergey Dyasli <sergey.dyasli@xxxxxxxxxx> v2: * Move MIN() into xen-tools/libs.h * Leave a TODO for the Xen/Viridian leaf infrastructure, and update the commit message * Rewrite copy_to_buffer_offset() to avoid multiple evaluation of its parameters * Change to an array typedef for constness reasons v3: * Rebase over libx86's movement * Remove unnecessary brackets in copy_to_buffer_offset() and include extra type safety --- 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 c766226..7980f9e 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 5e4ec09..51b6171 100644 --- a/xen/include/xen/lib/x86/cpuid.h +++ b/xen/include/xen/lib/x86/cpuid.h @@ -45,6 +45,19 @@ static inline void cpuid_count_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) @@ -248,6 +261,29 @@ void x86_cpuid_policy_fill_native(struct cpuid_policy *p); 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 ddd3821..f09d8d5 100644 --- a/xen/lib/x86/cpuid.c +++ b/xen/lib/x86/cpuid.c @@ -142,6 +142,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 8a7cf57..83cb653 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 */ -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |