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 <jbeulich@suse.com>
Signed-off-by: Penny Zheng <Penny.Zheng@amd.com>
---
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
© 2016 - 2025 Red Hat, Inc.