x86/cpuid: Rework HLE and RTM handling
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 20 May 2021 18:48:39 +0000 (19:48 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 27 May 2021 18:34:00 +0000 (19:34 +0100)
The TAA mitigation offered the option to hide the HLE and RTM CPUID bits,
which has caused some migration compatibility problems.

These two bits are special.  Annotate them with ! to emphasise this point.

Hardware Lock Elision (HLE) may or may not be visible in CPUID, but is
disabled in microcode on all CPUs, and has been removed from the architecture.
Do not advertise it to VMs by default.

Restricted Transactional Memory (RTM) may or may not be visible in CPUID, and
may or may not be configured in force-abort mode.  Have tsx_init() note
whether RTM has been configured into force-abort mode, so
guest_common_feature_adjustments() can conditionally hide it from VMs by
default.

The host policy values for HLE/RTM may or may not be set, depending on any
previous running kernel's choice of visibility, and Xen's choice.  TSX is
available on any CPU which enumerates a TSX-hiding mechanism, so instead of
doing a two-step to clobber any hiding, scan CPUID, then set the visibility,
just force visibility of the bits in the first place.

With the HLE/RTM bits now unilaterally visible in the host policy,
xc_cpuid_apply_policy() can construct a more appropriate policy out of thin
air for pre-4.13 VMs with no CPUID data in their migration stream, and
specifically one where HLE/RTM doesn't potentially disappear behind the back
of a running VM.

Fixes: 8c4330818f6 ("x86/spec-ctrl: Mitigate the TSX Asynchronous Abort sidechannel")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
tools/libs/guest/xg_cpuid_x86.c
xen/arch/x86/cpuid.c
xen/arch/x86/spec_ctrl.c
xen/arch/x86/tsx.c
xen/include/asm-x86/processor.h
xen/include/public/arch-x86/cpufeatureset.h

index 1ebc108213d50d9e52f7bcf14546a0b96d8b190e..ec5a47fde4ada1b607dc2d2a7a1739251c1549e8 100644 (file)
@@ -511,6 +511,8 @@ int xc_cpuid_apply_policy(xc_interface *xch, uint32_t domid, bool restore,
          * so migrated-in VM's don't risk seeing features disappearing.
          */
         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);
 
         if ( di.hvm )
         {
index 752bf244ea32fc04dbf1a247cd2fb660842bed7c..55a7b16342aa5a9a2c0d7de0128725c223822169 100644 (file)
@@ -375,6 +375,16 @@ static void __init guest_common_default_feature_adjustments(uint32_t *fs)
          boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x3a &&
          cpu_has_rdrand && !is_forced_cpu_cap(X86_FEATURE_RDRAND) )
         __clear_bit(X86_FEATURE_RDRAND, fs);
+
+    /*
+     * On certain hardware, speculative or errata workarounds can result in
+     * TSX being placed in "force-abort" mode, where it doesn't actually
+     * function as expected, but is technically compatible with the ISA.
+     *
+     * Do not advertise RTM to guests by default if it won't actually work.
+     */
+    if ( rtm_disabled )
+        __clear_bit(X86_FEATURE_RTM, fs);
 }
 
 static void __init guest_common_feature_adjustments(uint32_t *fs)
@@ -652,20 +662,6 @@ void recalculate_cpuid_policy(struct domain *d)
             __clear_bit(X86_FEATURE_SYSCALL, max_fs);
     }
 
-    /*
-     * On hardware with MSR_TSX_CTRL, the admin may have elected to disable
-     * TSX and hide the feature bits.  Migrating-in VMs may have been booted
-     * pre-mitigation when the TSX features were visbile.
-     *
-     * This situation is compatible (albeit with a perf hit to any TSX code in
-     * the guest), so allow the feature bits to remain set.
-     */
-    if ( cpu_has_tsx_ctrl )
-    {
-        __set_bit(X86_FEATURE_HLE, max_fs);
-        __set_bit(X86_FEATURE_RTM, max_fs);
-    }
-
     /* Clamp the toolstacks choices to reality. */
     for ( i = 0; i < ARRAY_SIZE(fs); i++ )
         fs[i] &= max_fs[i];
index cd05f4239413b689d92d2e57dba1b651426a57f6..f2782b2d5555c55f89d3450af3844fc1678a74b1 100644 (file)
@@ -1158,9 +1158,6 @@ void __init init_speculation_mitigations(void)
          ((hw_smt_enabled && opt_smt) ||
           !boot_cpu_has(X86_FEATURE_SC_VERW_IDLE)) )
     {
-        setup_clear_cpu_cap(X86_FEATURE_HLE);
-        setup_clear_cpu_cap(X86_FEATURE_RTM);
-
         opt_tsx = 0;
         tsx_init();
     }
index 39e483640aa13efdea5a206bfa1219e01a2f7c46..e09e819dce6213e7b025816bca760f6125eaa1a6 100644 (file)
@@ -15,6 +15,7 @@
  */
 int8_t __read_mostly opt_tsx = -1;
 int8_t __read_mostly cpu_has_tsx_ctrl = -1;
+bool __read_mostly rtm_disabled;
 
 static int __init parse_tsx(const char *s)
 {
@@ -45,6 +46,30 @@ void tsx_init(void)
             rdmsrl(MSR_ARCH_CAPABILITIES, caps);
 
         cpu_has_tsx_ctrl = !!(caps & ARCH_CAPS_TSX_CTRL);
+
+        /*
+         * The TSX features (HLE/RTM) are handled specially.  They both
+         * enumerate features but, on certain parts, have mechanisms to be
+         * hidden without disrupting running software.
+         *
+         * At the moment, we're running in an unknown context (WRT hiding -
+         * particularly if another fully fledged kernel ran before us) and
+         * depending on user settings, may elect to continue hiding them from
+         * native CPUID instructions.
+         *
+         * Xen doesn't use TSX itself, but use cpu_has_{hle,rtm} for various
+         * system reasons, mostly errata detection, so the meaning is more
+         * useful as "TSX infrastructure available", as opposed to "features
+         * advertised and working".
+         *
+         * Force the features to be visible in Xen's view if we see any of the
+         * infrastructure capable of hiding them.
+         */
+        if ( cpu_has_tsx_ctrl )
+        {
+            setup_force_cpu_cap(X86_FEATURE_HLE);
+            setup_force_cpu_cap(X86_FEATURE_RTM);
+        }
     }
 
     if ( cpu_has_tsx_ctrl )
@@ -53,9 +78,11 @@ void tsx_init(void)
 
         rdmsrl(MSR_TSX_CTRL, val);
 
+        /* Check bottom bit only.  Higher bits are various sentinels. */
+        rtm_disabled = !(opt_tsx & 1);
+
         val &= ~(TSX_CTRL_RTM_DISABLE | TSX_CTRL_CPUID_CLEAR);
-        /* Check bottom bit only.  Higher bits are various sentinals. */
-        if ( !(opt_tsx & 1) )
+        if ( rtm_disabled )
             val |= TSX_CTRL_RTM_DISABLE | TSX_CTRL_CPUID_CLEAR;
 
         wrmsrl(MSR_TSX_CTRL, val);
index 83143d4df8b7605b4b37d540d6471b95b9c1d685..bc4dc69253722798cc0dbbcdea5fd11944d2ee08 100644 (file)
@@ -627,6 +627,7 @@ static inline uint8_t get_cpu_family(uint32_t raw, uint8_t *model,
 }
 
 extern int8_t opt_tsx, cpu_has_tsx_ctrl;
+extern bool rtm_disabled;
 void tsx_init(void);
 
 enum ap_boot_method {
index c42f56bdd4fa2cfe18043809af4d67d77dc808b5..b65af424366ceb0712e79461d9a7c6423e4a6185 100644 (file)
@@ -197,14 +197,14 @@ XEN_CPUFEATURE(FSGSBASE,      5*32+ 0) /*A  {RD,WR}{FS,GS}BASE instructions */
 XEN_CPUFEATURE(TSC_ADJUST,    5*32+ 1) /*S  TSC_ADJUST MSR available */
 XEN_CPUFEATURE(SGX,           5*32+ 2) /*   Software Guard extensions */
 XEN_CPUFEATURE(BMI1,          5*32+ 3) /*A  1st bit manipulation extensions */
-XEN_CPUFEATURE(HLE,           5*32+ 4) /* Hardware Lock Elision */
+XEN_CPUFEATURE(HLE,           5*32+ 4) /*!a Hardware Lock Elision */
 XEN_CPUFEATURE(AVX2,          5*32+ 5) /*A  AVX2 instructions */
 XEN_CPUFEATURE(FDP_EXCP_ONLY, 5*32+ 6) /*!  x87 FDP only updated on exception. */
 XEN_CPUFEATURE(SMEP,          5*32+ 7) /*S  Supervisor Mode Execution Protection */
 XEN_CPUFEATURE(BMI2,          5*32+ 8) /*A  2nd bit manipulation extensions */
 XEN_CPUFEATURE(ERMS,          5*32+ 9) /*A  Enhanced REP MOVSB/STOSB */
 XEN_CPUFEATURE(INVPCID,       5*32+10) /*H  Invalidate Process Context ID */
-XEN_CPUFEATURE(RTM,           5*32+11) /* Restricted Transactional Memory */
+XEN_CPUFEATURE(RTM,           5*32+11) /*!A Restricted Transactional Memory */
 XEN_CPUFEATURE(PQM,           5*32+12) /*   Platform QoS Monitoring */
 XEN_CPUFEATURE(NO_FPU_SEL,    5*32+13) /*!  FPU CS/DS stored as zero */
 XEN_CPUFEATURE(MPX,           5*32+14) /*s  Memory Protection Extensions */