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
On 12.12.2025 05:01, Penny Zheng wrote: > --- 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 While I agree all three are needed here, ... > --- 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 ... none of them look to be needed e.g. here, and ... > --- 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 ... only two of them look to be needed e.g. here. Reason I was looking here again is that while talking of the split with the other x86 maintainers, we also discussed the option of moving what is being split out underneath xen/arch/x86/lib/. The way that may want doing, to some degree, depends on whether all "interested" parties want all the functions, which clearly isn't the case. Jan
On 12.12.2025 05:01, Penny Zheng wrote: > 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 At this point of the series there's no MGMT_HYPERCALLS yet (see also my reply to the cover letter). > 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 This looks to be doing at least three things in one go. If all of them would be simple (including them being a reasonably small diff), that may be fine. But the diffstat above says otherwise, so I may I ask that this be split in three, maybe even four pieces (one per function moving to a new file, and maybe one doing prep work in the Makefile-s touched)? The filenames also aren't very descriptive. cp-from-buffer.c, cp-to-buffer.c, and cp-clear.c maybe? Albeit the last one is where I'm the least convinced that splitting out and making a library function is actually a good idea. Note how I also didn't mention that function as a possible candidate for library- fying. I'll try to not forget to bring this up with the x86 maintainers later in the day. > --- 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 Why the mismatched padding on the := line? > --- 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) Why the intermediate libx86-y? And why is this not being done in xen/lib/x86/Makefile anyway? Jan
On 15.12.2025 13:14, Jan Beulich wrote: > On 12.12.2025 05:01, Penny Zheng wrote: >> 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 > > At this point of the series there's no MGMT_HYPERCALLS yet (see also my reply > to the cover letter). > >> 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 > > This looks to be doing at least three things in one go. If all of them would be > simple (including them being a reasonably small diff), that may be fine. But > the diffstat above says otherwise, so I may I ask that this be split in three, > maybe even four pieces (one per function moving to a new file, and maybe one > doing prep work in the Makefile-s touched)? > > The filenames also aren't very descriptive. cp-from-buffer.c, cp-to-buffer.c, > and cp-clear.c maybe? Albeit the last one is where I'm the least convinced > that splitting out and making a library function is actually a good idea. Note > how I also didn't mention that function as a possible candidate for library- > fying. I'll try to not forget to bring this up with the x86 maintainers later > in the day. Having discussed this, we thought we might as well aim for proper library fication (longer term, i.e. not something we'd ask you to do). Therefore splitting by function is generally okay, but the filenames really want to be sufficiently descriptive. For x86_cpu_policy_clear_out_of_range_leaves() this may very well mean cp-clear-out-of-range-leaves.c (not sure whether shortening to e.g. cp-clear-oor-leaves.c would make sense). Jan
© 2016 - 2026 Red Hat, Inc.