diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c index 512eb1f78f..a0202ecbc9 100644 --- a/tools/libxc/xc_cpuid_x86.c +++ b/tools/libxc/xc_cpuid_x86.c @@ -497,12 +497,22 @@ int xc_cpuid_apply_policy(xc_interface *xch, uint32_t domid, bool restore, goto out; } - /* - * Account for feature which have been disabled by default since Xen 4.13, - * so migrated-in VM's don't risk seeing features disappearing. - */ if ( restore ) { + /* + * Xen 4.14 introduced support to move the guest's CPUID data in the + * migration stream. Previously, the destination side would invent a + * policy out of thin air in the hopes that it was ok. + * + * This restore path is used for incoming VMs with no CPUID data + * i.e. originated on Xen 4.13 or earlier. We must invent a policy + * compatible with what Xen 4.13 would have done on the same hardware. + * + * Specifically: + * - Clamp max leaves. + * - Re-enable features which have become (possibly) off by default. + */ + p->basic.rdrand = test_bit(X86_FEATURE_RDRAND, host_featureset); p->feat.hle = test_bit(X86_FEATURE_HLE, host_featureset); p->feat.rtm = test_bit(X86_FEATURE_RTM, host_featureset); @@ -511,6 +521,10 @@ int xc_cpuid_apply_policy(xc_interface *xch, uint32_t domid, bool restore, { p->feat.mpx = test_bit(X86_FEATURE_MPX, host_featureset); } + + p->basic.max_leaf = min(p->basic.max_leaf, 0xdu); + p->feat.max_subleaf = 0; + p->extd.max_leaf = min(p->extd.max_leaf, 0x8000001c); } if ( featureset ) diff --git a/tools/libxl/libxl_cpuid.c b/tools/libxl/libxl_cpuid.c index ce93c5a796..a06f7a6606 100644 --- a/tools/libxl/libxl_cpuid.c +++ b/tools/libxl/libxl_cpuid.c @@ -290,6 +290,8 @@ int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str) {"svm_decode", 0x8000000a, NA, CPUID_REG_EDX, 7, 1}, {"svm_pausefilt",0x8000000a, NA, CPUID_REG_EDX, 10, 1}, + {"lfence+", 0x80000021, NA, CPUID_REG_EAX, 2, 1}, + {"maxhvleaf", 0x40000000, NA, CPUID_REG_EAX, 0, 8}, {NULL, 0, NA, CPUID_REG_INV, 0, 0} diff --git a/tools/misc/xen-cpuid.c b/tools/misc/xen-cpuid.c index 0056baf666..bfe20c0c5f 100644 --- a/tools/misc/xen-cpuid.c +++ b/tools/misc/xen-cpuid.c @@ -183,6 +183,11 @@ static const char *const str_7a1[32] = /* 4 */ [ 5] = "avx512_bf16", }; +static const char *const str_e21a[32] = +{ + [ 2] = "lfence+", +}; + static const struct { const char *name; const char *abbr; @@ -200,6 +205,7 @@ static const struct { { "0x80000008.ebx", "e8b", str_e8b }, { "0x00000007:0.edx", "7d0", str_7d0 }, { "0x00000007:1.eax", "7a1", str_7a1 }, + { "0x80000021.eax", "e21a", str_e21a }, }; #define COL_ALIGN "18" diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c index d33b7cf999..beff504842 100644 --- a/xen/arch/x86/cpu/amd.c +++ b/xen/arch/x86/cpu/amd.c @@ -646,6 +646,13 @@ void amd_init_lfence(struct cpuinfo_x86 *c) { uint64_t value; + /* + * Some hardware has LFENCE dispatch serialising always enabled, + * nothing to do on that case. + */ + if (test_bit(X86_FEATURE_LFENCE_DISPATCH, c->x86_capability)) + return; + /* * Attempt to set lfence to be Dispatch Serialising. This MSR almost * certainly isn't virtualised (and Xen at least will leak the real diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c index 743fbb65ab..8a37d863a8 100644 --- a/xen/arch/x86/cpu/common.c +++ b/xen/arch/x86/cpu/common.c @@ -419,6 +419,9 @@ static void generic_identify(struct cpuinfo_x86 *c) if (c->extended_cpuid_level >= 0x80000008) c->x86_capability[cpufeat_word(X86_FEATURE_CLZERO)] = cpuid_ebx(0x80000008); + if (c->extended_cpuid_level >= 0x80000021) + c->x86_capability[cpufeat_word(X86_FEATURE_LFENCE_DISPATCH)] + = cpuid_eax(0x80000021); /* Intel-defined flags: level 0x00000007 */ if ( c->cpuid_level >= 0x00000007 ) { diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index 5229eba595..390f4a5e56 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -308,6 +308,7 @@ static void __init calculate_raw_policy(void) static void __init calculate_host_policy(void) { struct cpuid_policy *p = &host_cpuid_policy; + unsigned int max_extd_leaf; *p = raw_cpuid_policy; @@ -315,7 +316,19 @@ static void __init calculate_host_policy(void) 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->extd.max_leaf = 0x80000000 | min_t(uint32_t, p->extd.max_leaf & 0xffff, + + max_extd_leaf = p->extd.max_leaf; + + /* + * For AMD/Hygon hardware before Zen3, we unilaterally modify LFENCE to be + * dispatch serialising for Spectre mitigations. Extend max_extd_leaf + * beyond what hardware supports, to include the feature leaf containing + * this information. + */ + if ( cpu_has_lfence_dispatch ) + max_extd_leaf = max(max_extd_leaf, 0x80000021); + + p->extd.max_leaf = 0x80000000 | min_t(uint32_t, max_extd_leaf & 0xffff, ARRAY_SIZE(p->extd.raw) - 1); cpuid_featureset_to_policy(boot_cpu_data.x86_capability, p); diff --git a/xen/include/asm-x86/cpufeatures.h b/xen/include/asm-x86/cpufeatures.h index d7e42d9bb6..6c8f432aee 100644 --- a/xen/include/asm-x86/cpufeatures.h +++ b/xen/include/asm-x86/cpufeatures.h @@ -24,7 +24,7 @@ XEN_CPUFEATURE(APERFMPERF, X86_SYNTH( 8)) /* APERFMPERF */ XEN_CPUFEATURE(MFENCE_RDTSC, X86_SYNTH( 9)) /* MFENCE synchronizes RDTSC */ XEN_CPUFEATURE(XEN_SMEP, X86_SYNTH(10)) /* SMEP gets used by Xen itself */ XEN_CPUFEATURE(XEN_SMAP, X86_SYNTH(11)) /* SMAP gets used by Xen itself */ -XEN_CPUFEATURE(LFENCE_DISPATCH, X86_SYNTH(12)) /* lfence set as Dispatch Serialising */ +/* Bit 12 - unused. */ XEN_CPUFEATURE(IND_THUNK_LFENCE, X86_SYNTH(13)) /* Use IND_THUNK_LFENCE */ XEN_CPUFEATURE(IND_THUNK_JMP, X86_SYNTH(14)) /* Use IND_THUNK_JMP */ XEN_CPUFEATURE(SC_BRANCH_HARDEN, X86_SYNTH(15)) /* Conditional Branch Hardening */ diff --git a/xen/include/public/arch-x86/cpufeatureset.h b/xen/include/public/arch-x86/cpufeatureset.h index c1b61385b1..bd74dd1a72 100644 --- a/xen/include/public/arch-x86/cpufeatureset.h +++ b/xen/include/public/arch-x86/cpufeatureset.h @@ -285,6 +285,9 @@ XEN_CPUFEATURE(SSBD, 9*32+31) /*A MSR_SPEC_CTRL.SSBD available */ /* Intel-defined CPU features, CPUID level 0x00000007:1.eax, word 10 */ XEN_CPUFEATURE(AVX512_BF16, 10*32+ 5) /*A AVX512 BFloat16 Instructions */ +/* AMD-defined CPU features, CPUID level 0x80000021.eax, word 11 */ +XEN_CPUFEATURE(LFENCE_DISPATCH, 11*32+ 2) /*A LFENCE always serializing */ + #endif /* XEN_CPUFEATURE */ /* Clean up from a default include. Close the enum (for C). */ diff --git a/xen/include/xen/lib/x86/cpuid.h b/xen/include/xen/lib/x86/cpuid.h index f4ef8a9f2f..a4d254ea96 100644 --- a/xen/include/xen/lib/x86/cpuid.h +++ b/xen/include/xen/lib/x86/cpuid.h @@ -15,6 +15,7 @@ #define FEATURESET_e8b 8 /* 0x80000008.ebx */ #define FEATURESET_7d0 9 /* 0x00000007:0.edx */ #define FEATURESET_7a1 10 /* 0x00000007:1.eax */ +#define FEATURESET_e21a 11 /* 0x80000021.eax */ struct cpuid_leaf { @@ -84,7 +85,7 @@ const char *x86_cpuid_vendor_to_str(unsigned int vendor); #define CPUID_GUEST_NR_TOPO (1u + 1) #define CPUID_GUEST_NR_XSTATE (62u + 1) #define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1) -#define CPUID_GUEST_NR_EXTD_AMD (0x1cu + 1) +#define CPUID_GUEST_NR_EXTD_AMD (0x21u + 1) #define CPUID_GUEST_NR_EXTD MAX(CPUID_GUEST_NR_EXTD_INTEL, \ CPUID_GUEST_NR_EXTD_AMD) @@ -264,6 +265,38 @@ struct cpuid_policy }; uint32_t nc:8, :4, apic_id_size:4, :16; uint32_t /* d */:32; + + uint64_t :64, :64; /* Leaf 0x80000009. */ + uint64_t :64, :64; /* Leaf 0x8000000a - SVM rev and features. */ + uint64_t :64, :64; /* Leaf 0x8000000b. */ + uint64_t :64, :64; /* Leaf 0x8000000c. */ + uint64_t :64, :64; /* Leaf 0x8000000d. */ + uint64_t :64, :64; /* Leaf 0x8000000e. */ + uint64_t :64, :64; /* Leaf 0x8000000f. */ + uint64_t :64, :64; /* Leaf 0x80000010. */ + uint64_t :64, :64; /* Leaf 0x80000011. */ + uint64_t :64, :64; /* Leaf 0x80000012. */ + uint64_t :64, :64; /* Leaf 0x80000013. */ + uint64_t :64, :64; /* Leaf 0x80000014. */ + uint64_t :64, :64; /* Leaf 0x80000015. */ + uint64_t :64, :64; /* Leaf 0x80000016. */ + uint64_t :64, :64; /* Leaf 0x80000017. */ + uint64_t :64, :64; /* Leaf 0x80000018. */ + uint64_t :64, :64; /* Leaf 0x80000019 - TLB 1GB Identifiers. */ + uint64_t :64, :64; /* Leaf 0x8000001a - Performance related info. */ + uint64_t :64, :64; /* Leaf 0x8000001b - IBS feature information. */ + uint64_t :64, :64; /* Leaf 0x8000001c. */ + uint64_t :64, :64; /* Leaf 0x8000001d - Cache properties. */ + uint64_t :64, :64; /* Leaf 0x8000001e - Extd APIC/Core/Node IDs. */ + uint64_t :64, :64; /* Leaf 0x8000001f - AMD Secure Encryption. */ + uint64_t :64, :64; /* Leaf 0x80000020 - Platform QoS. */ + + /* Leaf 0x80000021 - Extended Feature 2 */ + union { + uint32_t e21a; + struct { DECL_BITFIELD(e21a); }; + }; + uint32_t /* b */:32, /* c */:32, /* d */:32; }; } extd; @@ -293,6 +326,7 @@ static inline void cpuid_policy_to_featureset( fs[FEATURESET_e8b] = p->extd.e8b; fs[FEATURESET_7d0] = p->feat._7d0; fs[FEATURESET_7a1] = p->feat._7a1; + fs[FEATURESET_e21a] = p->extd.e21a; } /* Fill in a CPUID policy from a featureset bitmap. */ @@ -310,6 +344,7 @@ static inline void cpuid_featureset_to_policy( p->extd.e8b = fs[FEATURESET_e8b]; p->feat._7d0 = fs[FEATURESET_7d0]; p->feat._7a1 = fs[FEATURESET_7a1]; + p->extd.e21a = fs[FEATURESET_e21a]; } static inline uint64_t cpuid_policy_xcr0_max(const struct cpuid_policy *p)