@@ -210,7 +210,7 @@ static void recalculate_xstate(struct cp
if ( p->feat.mpx )
xstates |= X86_XCR0_BNDREGS | X86_XCR0_BNDCSR;
- if ( p->feat.avx512f )
+ if ( p->feat.avx512f || (p->feat.avx10 && p->avx10.vsz512) )
xstates |= X86_XCR0_OPMASK | X86_XCR0_ZMM | X86_XCR0_HI_ZMM;
if ( p->feat.pku )
@@ -268,6 +268,16 @@ static void recalculate_misc(struct cpu_
p->basic.raw[0xc] = EMPTY_LEAF;
+ zero_leaves(p->basic.raw, 0xe, 0x23);
+
+ p->avx10.raw[0].b &= 0x000700ff;
+ p->avx10.raw[0].c = p->avx10.raw[0].d = 0;
+ if ( !p->feat.avx10 || !p->avx10.version || !p->avx10.vsz512 )
+ {
+ p->feat.avx10 = false;
+ memset(p->avx10.raw, 0, sizeof(p->avx10.raw));
+ }
+
p->extd.e1d &= ~CPUID_COMMON_1D_FEATURES;
/* Most of Power/RAS hidden from guests. */
@@ -885,6 +895,7 @@ void recalculate_cpuid_policy(struct dom
p->basic.max_leaf = min(p->basic.max_leaf, max->basic.max_leaf);
p->feat.max_subleaf = min(p->feat.max_subleaf, max->feat.max_subleaf);
+ p->avx10.max_subleaf = min(p->avx10.max_subleaf, max->avx10.max_subleaf);
p->extd.max_leaf = 0x80000000U | min(p->extd.max_leaf & 0xffff,
((p->x86_vendor & (X86_VENDOR_AMD |
X86_VENDOR_HYGON))
@@ -931,6 +942,8 @@ void recalculate_cpuid_policy(struct dom
if ( p->basic.max_leaf < XSTATE_CPUID )
__clear_bit(X86_FEATURE_XSAVE, fs);
+ if ( p->basic.max_leaf < 0x24 )
+ __clear_bit(X86_FEATURE_AVX10, fs);
sanitise_featureset(fs);
@@ -1000,9 +1013,18 @@ void __init init_dom0_cpuid_policy(struc
/* Apply dom0-cpuid= command line settings, if provided. */
if ( dom0_cpuid_cmdline )
{
+ const struct cpu_policy *max = is_pv_domain(d)
+ ? (IS_ENABLED(CONFIG_PV) ? &pv_max_cpu_policy : NULL)
+ : (IS_ENABLED(CONFIG_HVM) ? &hvm_max_cpu_policy : NULL);
uint32_t fs[FSCAPINTS];
unsigned int i;
+ if ( !max )
+ {
+ ASSERT_UNREACHABLE();
+ return;
+ }
+
x86_cpu_policy_to_featureset(p, fs);
for ( i = 0; i < ARRAY_SIZE(fs); ++i )
@@ -1012,6 +1034,13 @@ void __init init_dom0_cpuid_policy(struc
}
x86_cpu_featureset_to_policy(fs, p);
+
+ /*
+ * Default-off features with their own leaves need those leaves
+ * re-populated from the max policy.
+ */
+ if ( p->feat.avx10 )
+ p->avx10 = max->avx10;
}
/*
@@ -1044,6 +1073,8 @@ static void __init __maybe_unused build_
sizeof(raw_cpu_policy.feat.raw));
BUILD_BUG_ON(sizeof(raw_cpu_policy.xstate) !=
sizeof(raw_cpu_policy.xstate.raw));
+ BUILD_BUG_ON(sizeof(raw_cpu_policy.avx10) !=
+ sizeof(raw_cpu_policy.avx10.raw));
BUILD_BUG_ON(sizeof(raw_cpu_policy.extd) !=
sizeof(raw_cpu_policy.extd.raw));
}
@@ -87,6 +87,15 @@ void guest_cpuid(const struct vcpu *v, u
*res = array_access_nospec(p->xstate.raw, subleaf);
break;
+ case 0x24:
+ ASSERT(p->avx10.max_subleaf < ARRAY_SIZE(p->avx10.raw));
+ if ( subleaf > min_t(uint32_t, p->avx10.max_subleaf,
+ ARRAY_SIZE(p->avx10.raw) - 1) )
+ return;
+
+ *res = array_access_nospec(p->avx10.raw, subleaf);
+ break;
+
default:
*res = array_access_nospec(p->basic.raw, leaf);
break;
@@ -334,6 +334,7 @@ XEN_CPUFEATURE(AVX_NE_CONVERT, 15*32
XEN_CPUFEATURE(AVX_VNNI_INT16, 15*32+10) /*A AVX-VNNI-INT16 Instructions */
XEN_CPUFEATURE(PREFETCHI, 15*32+14) /*A PREFETCHIT{0,1} Instructions */
XEN_CPUFEATURE(CET_SSS, 15*32+18) /* CET Supervisor Shadow Stacks safe to use */
+XEN_CPUFEATURE(AVX10, 15*32+19) /* AVX10 Converged Vector ISA */
/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.eax, word 16 */
XEN_CPUFEATURE(RDCL_NO, 16*32+ 0) /*A No Rogue Data Cache Load (Meltdown) */
@@ -85,11 +85,12 @@ unsigned int x86_cpuid_lookup_vendor(uin
*/
const char *x86_cpuid_vendor_to_str(unsigned int vendor);
-#define CPUID_GUEST_NR_BASIC (0xdu + 1)
+#define CPUID_GUEST_NR_BASIC (0x24u + 1)
#define CPUID_GUEST_NR_CACHE (5u + 1)
#define CPUID_GUEST_NR_FEAT (2u + 1)
#define CPUID_GUEST_NR_TOPO (1u + 1)
#define CPUID_GUEST_NR_XSTATE (62u + 1)
+#define CPUID_GUEST_NR_AVX10 (0u + 1)
#define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1)
#define CPUID_GUEST_NR_EXTD_AMD (0x21u + 1)
#define CPUID_GUEST_NR_EXTD MAX(CPUID_GUEST_NR_EXTD_INTEL, \
@@ -255,6 +256,19 @@ struct cpu_policy
} comp[CPUID_GUEST_NR_XSTATE];
} xstate;
+ /* Structured AVX10 information leaf: 0x000000024[xx] */
+ union {
+ struct cpuid_leaf raw[CPUID_GUEST_NR_AVX10];
+ struct {
+ /* Subleaf 0. */
+ uint32_t max_subleaf;
+ uint32_t version:8, :9;
+ bool vsz256:1, vsz512:1;
+ uint32_t :13;
+ uint32_t /* c */:32, /* d */:32;
+ };
+ } avx10;
+
/* Extended leaves: 0x800000xx */
union {
struct cpuid_leaf raw[CPUID_GUEST_NR_EXTD];
@@ -123,6 +123,7 @@ void x86_cpu_policy_fill_native(struct c
switch ( i )
{
case 0x4: case 0x7: case 0xb: case 0xd:
+ case 0x24:
/* Multi-invocation leaves. Deferred. */
continue;
}
@@ -216,6 +217,15 @@ void x86_cpu_policy_fill_native(struct c
}
}
+ if ( p->basic.max_leaf >= 0x24 )
+ {
+ cpuid_count_leaf(0x24, 0, &p->avx10.raw[0]);
+
+ for ( i = 1; i <= MIN(p->avx10.max_subleaf,
+ ARRAY_SIZE(p->avx10.raw) - 1); ++i )
+ cpuid_count_leaf(0x24, i, &p->avx10.raw[i]);
+ }
+
/* Extended leaves. */
cpuid_leaf(0x80000000U, &p->extd.raw[0]);
for ( i = 1; i <= MIN(p->extd.max_leaf & 0xffffU,
@@ -285,6 +295,9 @@ void x86_cpu_policy_clear_out_of_range_l
ARRAY_SIZE(p->xstate.raw) - 1);
}
+ if ( p->basic.max_leaf < 0x24 )
+ memset(p->avx10.raw, 0, sizeof(p->avx10.raw));
+
zero_leaves(p->extd.raw,
((p->extd.max_leaf >> 16) == 0x8000
? (p->extd.max_leaf & 0xffff) + 1 : 0),
@@ -297,6 +310,8 @@ void __init x86_cpu_policy_bound_max_lea
min_t(uint32_t, p->basic.max_leaf, ARRAY_SIZE(p->basic.raw) - 1);
p->feat.max_subleaf =
min_t(uint32_t, p->feat.max_subleaf, ARRAY_SIZE(p->feat.raw) - 1);
+ p->avx10.max_subleaf =
+ min_t(uint32_t, p->avx10.max_subleaf, ARRAY_SIZE(p->avx10.raw) - 1);
p->extd.max_leaf = 0x80000000U | min_t(uint32_t, p->extd.max_leaf & 0xffff,
ARRAY_SIZE(p->extd.raw) - 1);
}
@@ -324,6 +339,8 @@ void x86_cpu_policy_shrink_max_leaves(st
*/
p->basic.raw[0xd] = p->xstate.raw[0];
+ p->basic.raw[0x24] = p->avx10.raw[0];
+
for ( i = p->basic.max_leaf; i; --i )
if ( p->basic.raw[i].a | p->basic.raw[i].b |
p->basic.raw[i].c | p->basic.raw[i].d )
@@ -457,6 +474,13 @@ int x86_cpuid_copy_to_buffer(const struc
break;
}
+ case 0x24:
+ for ( subleaf = 0;
+ subleaf <= MIN(p->avx10.max_subleaf,
+ ARRAY_SIZE(p->avx10.raw) - 1); ++subleaf )
+ COPY_LEAF(leaf, subleaf, &p->avx10.raw[subleaf]);
+ break;
+
default:
COPY_LEAF(leaf, XEN_CPUID_NO_SUBLEAF, &p->basic.raw[leaf]);
break;
@@ -549,6 +573,13 @@ int x86_cpuid_copy_from_buffer(struct cp
array_access_nospec(p->xstate.raw, data.subleaf) = l;
break;
+ case 0x24:
+ if ( data.subleaf >= ARRAY_SIZE(p->avx10.raw) )
+ goto out_of_range;
+
+ array_access_nospec(p->avx10.raw, data.subleaf) = l;
+ break;
+
default:
if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
goto out_of_range;
@@ -21,6 +21,12 @@ int x86_cpu_policies_are_compatible(cons
if ( guest->feat.max_subleaf > host->feat.max_subleaf )
FAIL_CPUID(7, 0);
+ if ( guest->avx10.version > host->avx10.version ||
+ (guest->avx10.vsz512
+ ? !host->avx10.vsz512
+ : guest->avx10.vsz256 && !host->avx10.vsz256 && !host->avx10.vsz512) )
+ FAIL_CPUID(0x24, 0);
+
if ( guest->extd.max_leaf > host->extd.max_leaf )
FAIL_CPUID(0x80000000U, NA);
@@ -285,7 +285,7 @@ def crunch_numbers(state):
# enabled. Certain later extensions, acting on 256-bit vectors of
# integers, better depend on AVX2 than AVX.
AVX2: [AVX512F, VAES, VPCLMULQDQ, AVX_VNNI, AVX_IFMA, AVX_VNNI_INT8,
- AVX_VNNI_INT16, SHA512, SM4],
+ AVX_VNNI_INT16, SHA512, SM4, AVX10],
# AVX512F is taken to mean hardware support for 512bit registers
# (which in practice depends on the EVEX prefix to encode) as well
This requires bumping the number of basic leaves we support. Apart from this the logic is modeled as closely as possible after that of leaf 7 handling. Signed-off-by: Jan Beulich <jbeulich@suse.com> --- The gen-cpuid.py adjustment is merely the minimum needed. It's not really clear to me whether someone turning off e.g. AVX512BW might then also validly expect AVX10 to be turned off. Spec version 2 leaves unclear what the xstate components are which would need enabling for AVX10/256. recalculate_{xstate,misc}() are therefore conservative for now. Do we want to synthesize AVX10 in the policy when all necessary AVX512* features are available, thus allowing migration from an AVX10 host to a suitable non-AVX10 one? How a toolstack side equivalent (if any) of the init_dom0_cpuid_policy() change would look like is entirely unclear to me. How much should we take from the max policy, and how much should we require the user to specify (and how would the latter look like)? --- v2: Add logic to init_dom0_cpuid_policy(). Drop vsz128 field. Re-base.