There are some cpuid library functions only referenced in XEN_DOMCTL-case, and shall be wrapped with CONFIG_MGMT_HYPERCALLS later, otherwise they will become unreachable when MGMT_HYPERCALLS=n, and hence violate Misra 2.1 For file cpupolicy-clr.c to contain cpupolicy clearing library function: - x86_cpu_policy_clear_out_of_range_leaves - zero_leaves For file cpuid-cp2buf.c to contain cpuid copy-to-buffer library function: - x86_cpuid_copy_to_buffer - copy_leaf_to_buffer For file cpuid-cpfrbuf.c to contain cpuid copy-from-buffer library function: - x86_cpuid_copy_from_buffer Sunmmerize all needed cpuid-library object file under a new variable CPUID_OBJS in Makefile.
Suggested-by: Jan Beulich <[email protected]> Signed-off-by: Penny Zheng <[email protected]> --- v4 -> v5: - library-fy cpuid-releated functions --- tools/fuzz/cpu-policy/Makefile | 4 +- tools/fuzz/x86_instruction_emulator/Makefile | 11 +- tools/libs/guest/Makefile.common | 4 +- tools/tests/cpu-policy/Makefile | 3 +- tools/tests/x86_emulator/Makefile | 3 +- xen/lib/Makefile | 5 + xen/lib/x86/cpuid-cp2buf.c | 123 ++++++++ xen/lib/x86/cpuid-cpfrbuf.c | 129 +++++++++ xen/lib/x86/cpuid.c | 286 ------------------- xen/lib/x86/cpupolicy-clr.c | 73 +++++ 10 files changed, 346 insertions(+), 295 deletions(-) create mode 100644 xen/lib/x86/cpuid-cp2buf.c create mode 100644 xen/lib/x86/cpuid-cpfrbuf.c create mode 100644 xen/lib/x86/cpupolicy-clr.c diff --git a/tools/fuzz/cpu-policy/Makefile b/tools/fuzz/cpu-policy/Makefile index 6e7743e0aa..543d265e62 100644 --- a/tools/fuzz/cpu-policy/Makefile +++ b/tools/fuzz/cpu-policy/Makefile @@ -22,7 +22,9 @@ CFLAGS += $(APPEND_CFLAGS) -Og vpath %.c ../../../xen/lib/x86 -afl-policy-fuzzer: afl-policy-fuzzer.o msr.o cpuid.o +CPUID_OBJS := cpuid.o cpuid-cp2buf.o cpuid-cpfrbuf.o cpupolicy-clr.o +afl-policy-fuzzer: afl-policy-fuzzer.o msr.o $(CPUID_OBJS) + $(CC) $(CFLAGS) $^ -o $@ -include $(DEPS_INCLUDE) diff --git a/tools/fuzz/x86_instruction_emulator/Makefile b/tools/fuzz/x86_instruction_emulator/Makefile index 459743f4d9..7a0ca79db8 100644 --- a/tools/fuzz/x86_instruction_emulator/Makefile +++ b/tools/fuzz/x86_instruction_emulator/Makefile @@ -25,7 +25,8 @@ x86_emulate/%.h: x86_emulate ; ln -nsf $< $@ CFLAGS += $(CFLAGS_xeninclude) -D__XEN_TOOLS__ -iquote . -cpuid.o: CFLAGS += -iquote $(XEN_ROOT)/xen/lib/x86 +CPUID_OBJS := cpuid.o cpuid-cp2buf.o cpuid-cpfrbuf.o cpupolicy-clr.o +$(CPUID_OBJS): CFLAGS += -iquote $(XEN_ROOT)/xen/lib/x86 GCOV_FLAGS := --coverage %-cov.o: %.c @@ -49,16 +50,16 @@ $(filter x86_emulate/%.o,$(OBJS)): x86_emulate/%.o: x86_emulate/%.c $(private.h) $(patsubst %.o,%-cov.o,$(filter x86_emulate/%.o,$(OBJS))): x86_emulate/%-cov.o: x86_emulate/%.c $(private.h) $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_$*.o) $(GCOV_FLAGS) -c -o $@ $< $(APPEND_CFLAGS) -x86-insn-fuzzer.a: $(OBJS) cpuid.o +x86-insn-fuzzer.a: $(OBJS) $(CPUID_OBJS) $(AR) rc $@ $^ -afl-harness: afl-harness.o $(OBJS) cpuid.o wrappers.o +afl-harness: afl-harness.o $(OBJS) $(CPUID_OBJS) wrappers.o $(CC) $(CFLAGS) $(addprefix -Wl$(comma)--wrap=,$(WRAPPED)) $^ -o $@ -afl-harness-cov: afl-harness-cov.o $(patsubst %.o,%-cov.o,$(OBJS)) cpuid.o wrappers.o +afl-harness-cov: afl-harness-cov.o $(patsubst %.o,%-cov.o,$(OBJS)) $(CPUID_OBJS) wrappers.o $(CC) $(CFLAGS) $(GCOV_FLAGS) $(addprefix -Wl$(comma)--wrap=,$(WRAPPED)) $^ -o $@ -libfuzzer-harness: $(OBJS) cpuid.o wrappers.o +libfuzzer-harness: $(OBJS) $(CPUID_OBJS) wrappers.o $(CC) $(CFLAGS) $(LIB_FUZZING_ENGINE) -fsanitize=fuzzer $(addprefix -Wl$(comma)--wrap=,$(WRAPPED)) $^ -o $@ # Common targets diff --git a/tools/libs/guest/Makefile.common b/tools/libs/guest/Makefile.common index a026a2f662..7dee6c0e0b 100644 --- a/tools/libs/guest/Makefile.common +++ b/tools/libs/guest/Makefile.common @@ -35,7 +35,9 @@ OBJS-y += $(LIBELF_OBJS) ifeq ($(CONFIG_X86),y) # Add libx86 to the build vpath %.c ../../../xen/lib/x86 -OBJS-y += cpuid.o msr.o policy.o +CPUID_OBJS := cpuid.o cpuid-cp2buf.o cpuid-cpfrbuf.o cpupolicy-clr.o +OBJS-y += $(CPUID_OBJS) +OBJS-y += msr.o policy.o endif # new domain builder diff --git a/tools/tests/cpu-policy/Makefile b/tools/tests/cpu-policy/Makefile index 24f87e2eca..f99a8b3ea2 100644 --- a/tools/tests/cpu-policy/Makefile +++ b/tools/tests/cpu-policy/Makefile @@ -46,7 +46,8 @@ vpath %.c ../../../xen/lib/x86 %.o: Makefile -test-cpu-policy: test-cpu-policy.o msr.o cpuid.o policy.o +CPUID_OBJS := cpuid.o cpuid-cp2buf.o cpuid-cpfrbuf.o cpupolicy-clr.o +test-cpu-policy: test-cpu-policy.o msr.o $(CPUID_OBJS) policy.o $(CC) $^ -o $@ $(LDFLAGS) -include $(DEPS_INCLUDE) diff --git a/tools/tests/x86_emulator/Makefile b/tools/tests/x86_emulator/Makefile index 3e02580a35..2f2bf933d3 100644 --- a/tools/tests/x86_emulator/Makefile +++ b/tools/tests/x86_emulator/Makefile @@ -248,7 +248,8 @@ xop.h avx512f.h avx512fp16.h: simd-fma.c endif # 32-bit override -OBJS := x86-emulate.o cpuid.o test_x86_emulator.o evex-disp8.o predicates.o wrappers.o +CPUID_OBJS := cpuid.o cpuid-cp2buf.o cpuid-cpfrbuf.o cpupolicy-clr.o +OBJS := x86-emulate.o $(CPUID_OBJS) test_x86_emulator.o evex-disp8.o predicates.o wrappers.o OBJS += x86_emulate/0f01.o x86_emulate/0fae.o x86_emulate/0fc7.o OBJS += x86_emulate/blk.o x86_emulate/decode.o x86_emulate/fpu.o x86_emulate/util.o diff --git a/xen/lib/Makefile b/xen/lib/Makefile index efca830d92..9b3e03a511 100644 --- a/xen/lib/Makefile +++ b/xen/lib/Makefile @@ -45,3 +45,8 @@ lib-$(CONFIG_X86) += xxhash64.o lib32-y := divmod.o lib32-$(CONFIG_64BIT) := lib-y += $(lib32-y) + +libx86-y := x86/cpuid-cp2buf.o +libx86-y += x86/cpuid-cpfrbuf.o +libx86-y += x86/cpupolicy-clr.o +lib-$(CONFIG_X86) += $(libx86-y) diff --git a/xen/lib/x86/cpuid-cp2buf.c b/xen/lib/x86/cpuid-cp2buf.c new file mode 100644 index 0000000000..144d915ad9 --- /dev/null +++ b/xen/lib/x86/cpuid-cp2buf.c @@ -0,0 +1,123 @@ +#include "private.h" + +#include <xen/lib/x86/cpu-policy.h> + +/* + * 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 cpu_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]); + + if ( p->cache.subleaf[subleaf].type == 0 ) + break; + } + 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]); + + if ( p->topo.subleaf[subleaf].type == 0 ) + break; + } + break; + + case 0xd: + { + uint64_t xstates = cpu_policy_xstates(p); + + COPY_LEAF(leaf, 0, &p->xstate.raw[0]); + COPY_LEAF(leaf, 1, &p->xstate.raw[1]); + + for ( xstates >>= 2, subleaf = 2; + xstates && subleaf < ARRAY_SIZE(p->xstate.raw); + xstates >>= 1, ++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(0x80000000U | 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" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/lib/x86/cpuid-cpfrbuf.c b/xen/lib/x86/cpuid-cpfrbuf.c new file mode 100644 index 0000000000..41eb7ee250 --- /dev/null +++ b/xen/lib/x86/cpuid-cpfrbuf.c @@ -0,0 +1,129 @@ +#include "private.h" + +#include <xen/lib/x86/cpu-policy.h> + +int x86_cpuid_copy_from_buffer(struct cpu_policy *p, + const cpuid_leaf_buffer_t leaves, + uint32_t nr_entries, uint32_t *err_leaf, + uint32_t *err_subleaf) +{ + unsigned int i; + xen_cpuid_leaf_t data; + + if ( err_leaf ) + *err_leaf = -1; + if ( err_subleaf ) + *err_subleaf = -1; + + /* + * A well formed caller is expected to pass an array with leaves in order, + * and without any repetitions. However, due to per-vendor differences, + * and in the case of upgrade or levelled scenarios, we typically expect + * fewer than MAX leaves to be passed. + * + * Detecting repeated entries is prohibitively complicated, so we don't + * bother. That said, one way or another if more than MAX leaves are + * passed, something is wrong. + */ + if ( nr_entries > CPUID_MAX_SERIALISED_LEAVES ) + return -E2BIG; + + for ( i = 0; i < nr_entries; ++i ) + { + struct cpuid_leaf l; + + if ( copy_from_buffer_offset(&data, leaves, i, 1) ) + return -EFAULT; + + l = (struct cpuid_leaf){ data.a, data.b, data.c, data.d }; + + switch ( data.leaf ) + { + case 0 ... ARRAY_SIZE(p->basic.raw) - 1: + switch ( data.leaf ) + { + case 0x4: + if ( data.subleaf >= ARRAY_SIZE(p->cache.raw) ) + goto out_of_range; + + array_access_nospec(p->cache.raw, data.subleaf) = l; + break; + + case 0x7: + if ( data.subleaf >= ARRAY_SIZE(p->feat.raw) ) + goto out_of_range; + + array_access_nospec(p->feat.raw, data.subleaf) = l; + break; + + case 0xb: + if ( data.subleaf >= ARRAY_SIZE(p->topo.raw) ) + goto out_of_range; + + array_access_nospec(p->topo.raw, data.subleaf) = l; + break; + + case 0xd: + if ( data.subleaf >= ARRAY_SIZE(p->xstate.raw) ) + goto out_of_range; + + array_access_nospec(p->xstate.raw, data.subleaf) = l; + break; + + default: + if ( data.subleaf != XEN_CPUID_NO_SUBLEAF ) + goto out_of_range; + + array_access_nospec(p->basic.raw, data.leaf) = l; + break; + } + break; + + case 0x40000000: + if ( data.subleaf != XEN_CPUID_NO_SUBLEAF ) + goto out_of_range; + + p->hv_limit = l.a; + break; + + case 0x40000100: + if ( data.subleaf != XEN_CPUID_NO_SUBLEAF ) + goto out_of_range; + + p->hv2_limit = l.a; + break; + + case 0x80000000U ... 0x80000000U + ARRAY_SIZE(p->extd.raw) - 1: + if ( data.subleaf != XEN_CPUID_NO_SUBLEAF ) + goto out_of_range; + + array_access_nospec(p->extd.raw, data.leaf & 0xffff) = l; + break; + + default: + goto out_of_range; + } + } + + x86_cpu_policy_recalc_synth(p); + + return 0; + + out_of_range: + if ( err_leaf ) + *err_leaf = data.leaf; + if ( err_subleaf ) + *err_subleaf = data.subleaf; + + return -ERANGE; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/lib/x86/cpuid.c b/xen/lib/x86/cpuid.c index 6298d051f2..465bdee35a 100644 --- a/xen/lib/x86/cpuid.c +++ b/xen/lib/x86/cpuid.c @@ -2,13 +2,6 @@ #include <xen/lib/x86/cpu-policy.h> -static void zero_leaves(struct cpuid_leaf *l, - unsigned int first, unsigned int last) -{ - if ( first <= last ) - memset(&l[first], 0, sizeof(*l) * (last - first + 1)); -} - unsigned int x86_cpuid_lookup_vendor(uint32_t ebx, uint32_t ecx, uint32_t edx) { switch ( ebx ) @@ -238,59 +231,6 @@ void x86_cpu_policy_fill_native(struct cpu_policy *p) x86_cpu_policy_recalc_synth(p); } -void x86_cpu_policy_clear_out_of_range_leaves(struct cpu_policy *p) -{ - unsigned int i; - - zero_leaves(p->basic.raw, p->basic.max_leaf + 1, - ARRAY_SIZE(p->basic.raw) - 1); - - if ( p->basic.max_leaf < 4 ) - memset(p->cache.raw, 0, sizeof(p->cache.raw)); - else - { - for ( i = 0; (i < ARRAY_SIZE(p->cache.raw) && - p->cache.subleaf[i].type); ++i ) - ; - - zero_leaves(p->cache.raw, i, ARRAY_SIZE(p->cache.raw) - 1); - } - - if ( p->basic.max_leaf < 7 ) - memset(p->feat.raw, 0, sizeof(p->feat.raw)); - else - zero_leaves(p->feat.raw, p->feat.max_subleaf + 1, - ARRAY_SIZE(p->feat.raw) - 1); - - if ( p->basic.max_leaf < 0xb ) - memset(p->topo.raw, 0, sizeof(p->topo.raw)); - else - { - for ( i = 0; (i < ARRAY_SIZE(p->topo.raw) && - p->topo.subleaf[i].type); ++i ) - ; - - zero_leaves(p->topo.raw, i, ARRAY_SIZE(p->topo.raw) - 1); - } - - if ( p->basic.max_leaf < 0xd || !cpu_policy_xstates(p) ) - memset(p->xstate.raw, 0, sizeof(p->xstate.raw)); - else - { - /* This logic will probably need adjusting when XCR0[63] gets used. */ - BUILD_BUG_ON(ARRAY_SIZE(p->xstate.raw) > 63); - - /* First two leaves always valid. Rest depend on xstates. */ - i = max(2, 64 - __builtin_clzll(cpu_policy_xstates(p))); - - zero_leaves(p->xstate.raw, i, - ARRAY_SIZE(p->xstate.raw) - 1); - } - - zero_leaves(p->extd.raw, (p->extd.max_leaf & 0xffff) + 1, - ARRAY_SIZE(p->extd.raw) - 1); -} - const uint32_t *x86_cpu_policy_lookup_deep_deps(uint32_t feature) { static const uint32_t deep_features[] = INIT_DEEP_FEATURES; @@ -322,232 +262,6 @@ const uint32_t *x86_cpu_policy_lookup_deep_deps(uint32_t feature) 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 cpu_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]); - - if ( p->cache.subleaf[subleaf].type == 0 ) - break; - } - 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]); - - if ( p->topo.subleaf[subleaf].type == 0 ) - break; - } - break; - - case 0xd: - { - uint64_t xstates = cpu_policy_xstates(p); - - COPY_LEAF(leaf, 0, &p->xstate.raw[0]); - COPY_LEAF(leaf, 1, &p->xstate.raw[1]); - - for ( xstates >>= 2, subleaf = 2; - xstates && subleaf < ARRAY_SIZE(p->xstate.raw); - xstates >>= 1, ++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(0x80000000U | leaf, XEN_CPUID_NO_SUBLEAF, &p->extd.raw[leaf]); - -#undef COPY_LEAF - - *nr_entries_p = curr_entry; - - return 0; -} - -int x86_cpuid_copy_from_buffer(struct cpu_policy *p, - const cpuid_leaf_buffer_t leaves, - uint32_t nr_entries, uint32_t *err_leaf, - uint32_t *err_subleaf) -{ - unsigned int i; - xen_cpuid_leaf_t data; - - if ( err_leaf ) - *err_leaf = -1; - if ( err_subleaf ) - *err_subleaf = -1; - - /* - * A well formed caller is expected to pass an array with leaves in order, - * and without any repetitions. However, due to per-vendor differences, - * and in the case of upgrade or levelled scenarios, we typically expect - * fewer than MAX leaves to be passed. - * - * Detecting repeated entries is prohibitively complicated, so we don't - * bother. That said, one way or another if more than MAX leaves are - * passed, something is wrong. - */ - if ( nr_entries > CPUID_MAX_SERIALISED_LEAVES ) - return -E2BIG; - - for ( i = 0; i < nr_entries; ++i ) - { - struct cpuid_leaf l; - - if ( copy_from_buffer_offset(&data, leaves, i, 1) ) - return -EFAULT; - - l = (struct cpuid_leaf){ data.a, data.b, data.c, data.d }; - - switch ( data.leaf ) - { - case 0 ... ARRAY_SIZE(p->basic.raw) - 1: - switch ( data.leaf ) - { - case 0x4: - if ( data.subleaf >= ARRAY_SIZE(p->cache.raw) ) - goto out_of_range; - - array_access_nospec(p->cache.raw, data.subleaf) = l; - break; - - case 0x7: - if ( data.subleaf >= ARRAY_SIZE(p->feat.raw) ) - goto out_of_range; - - array_access_nospec(p->feat.raw, data.subleaf) = l; - break; - - case 0xb: - if ( data.subleaf >= ARRAY_SIZE(p->topo.raw) ) - goto out_of_range; - - array_access_nospec(p->topo.raw, data.subleaf) = l; - break; - - case 0xd: - if ( data.subleaf >= ARRAY_SIZE(p->xstate.raw) ) - goto out_of_range; - - array_access_nospec(p->xstate.raw, data.subleaf) = l; - break; - - default: - if ( data.subleaf != XEN_CPUID_NO_SUBLEAF ) - goto out_of_range; - - array_access_nospec(p->basic.raw, data.leaf) = l; - break; - } - break; - - case 0x40000000: - if ( data.subleaf != XEN_CPUID_NO_SUBLEAF ) - goto out_of_range; - - p->hv_limit = l.a; - break; - - case 0x40000100: - if ( data.subleaf != XEN_CPUID_NO_SUBLEAF ) - goto out_of_range; - - p->hv2_limit = l.a; - break; - - case 0x80000000U ... 0x80000000U + ARRAY_SIZE(p->extd.raw) - 1: - if ( data.subleaf != XEN_CPUID_NO_SUBLEAF ) - goto out_of_range; - - array_access_nospec(p->extd.raw, data.leaf & 0xffff) = l; - break; - - default: - goto out_of_range; - } - } - - x86_cpu_policy_recalc_synth(p); - - return 0; - - out_of_range: - if ( err_leaf ) - *err_leaf = data.leaf; - if ( err_subleaf ) - *err_subleaf = data.subleaf; - - return -ERANGE; -} - /* * Local variables: * mode: C diff --git a/xen/lib/x86/cpupolicy-clr.c b/xen/lib/x86/cpupolicy-clr.c new file mode 100644 index 0000000000..de090a7c95 --- /dev/null +++ b/xen/lib/x86/cpupolicy-clr.c @@ -0,0 +1,73 @@ +#include "private.h" + +#include <xen/lib/x86/cpu-policy.h> + +static void zero_leaves(struct cpuid_leaf *l, + unsigned int first, unsigned int last) +{ + if ( first <= last ) + memset(&l[first], 0, sizeof(*l) * (last - first + 1)); +} + +void x86_cpu_policy_clear_out_of_range_leaves(struct cpu_policy *p) +{ + unsigned int i; + + zero_leaves(p->basic.raw, p->basic.max_leaf + 1, + ARRAY_SIZE(p->basic.raw) - 1); + + if ( p->basic.max_leaf < 4 ) + memset(p->cache.raw, 0, sizeof(p->cache.raw)); + else + { + for ( i = 0; (i < ARRAY_SIZE(p->cache.raw) && + p->cache.subleaf[i].type); ++i ) + ; + + zero_leaves(p->cache.raw, i, ARRAY_SIZE(p->cache.raw) - 1); + } + + if ( p->basic.max_leaf < 7 ) + memset(p->feat.raw, 0, sizeof(p->feat.raw)); + else + zero_leaves(p->feat.raw, p->feat.max_subleaf + 1, + ARRAY_SIZE(p->feat.raw) - 1); + + if ( p->basic.max_leaf < 0xb ) + memset(p->topo.raw, 0, sizeof(p->topo.raw)); + else + { + for ( i = 0; (i < ARRAY_SIZE(p->topo.raw) && + p->topo.subleaf[i].type); ++i ) + ; + + zero_leaves(p->topo.raw, i, ARRAY_SIZE(p->topo.raw) - 1); + } + + if ( p->basic.max_leaf < 0xd || !cpu_policy_xstates(p) ) + memset(p->xstate.raw, 0, sizeof(p->xstate.raw)); + else + { + /* This logic will probably need adjusting when XCR0[63] gets used. */ + BUILD_BUG_ON(ARRAY_SIZE(p->xstate.raw) > 63); + + /* First two leaves always valid. Rest depend on xstates. */ + i = max(2, 64 - __builtin_clzll(cpu_policy_xstates(p))); + + zero_leaves(p->xstate.raw, i, + ARRAY_SIZE(p->xstate.raw) - 1); + } + + zero_leaves(p->extd.raw, (p->extd.max_leaf & 0xffff) + 1, + ARRAY_SIZE(p->extd.raw) - 1); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ -- 2.34.1
