]> xenbits.xensource.com Git - xen.git/commitdiff
x86/tsx: Introduce tsx= to use MSR_TSX_CTRL when available
authorAndrew Cooper <andrew.cooper3@citrix.com>
Wed, 19 Jun 2019 17:16:03 +0000 (18:16 +0100)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 12 Nov 2019 17:17:58 +0000 (17:17 +0000)
To protect against the TSX Async Abort speculative vulnerability, Intel have
released new microcode for affected parts which introduce the MSR_TSX_CTRL
control, which allows TSX to be turned off.  This will be architectural on
future parts.

Introduce tsx= to provide a global on/off for TSX, including its enumeration
via CPUID.  Provide stub virtualisation of this MSR, as it is not exposed to
guests at the moment.

VMs may have booted before microcode is loaded, or before hosts have rebooted,
and they still want to migrate freely.  A VM which booted seeing TSX can
migrate safely to hosts with TSX disabled - TSX will start unconditionally
aborting, but still behave in a manner compatible with the ABI.

The guest-visible behaviour is equivalent to late loading the microcode and
setting the RTM_DISABLE bit in the course of live patching.

This is part of XSA-305 / CVE-2019-11135

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
docs/misc/xen-command-line.markdown
xen/arch/x86/Makefile
xen/arch/x86/hvm/hvm.c
xen/arch/x86/setup.c
xen/arch/x86/smpboot.c
xen/arch/x86/traps.c
xen/arch/x86/tsx.c [new file with mode: 0644]
xen/include/asm-x86/msr-index.h
xen/include/asm-x86/processor.h
xen/include/xen/lib.h

index 7f60ddbbc644e57b330776f50c86e32fe7a51e6e..28fcceb6fccb7722f71d57d1e5c126d75f7ede08 100644 (file)
@@ -1727,6 +1727,20 @@ pages) must also be specified via the tbuf\_size parameter.
 ### tsc
 > `= unstable | skewed | stable:socket`
 
+### tsx
+    = <bool>
+
+    Applicability: x86
+    Default: true
+
+Controls for the use of Transactional Synchronization eXtensions.
+
+On Intel parts released in Q3 2019 (with updated microcode), and future parts,
+a control has been introduced which allows TSX to be turned off.
+
+On systems with the ability to turn TSX off, this boolean offers system wide
+control of whether TSX is enabled or disabled.
+
 ### ucode
 > `= [<integer> | scan]`
 
index fc90449ea3b442bd1906355c388590ea200f37c5..09e7a1096d4189794eb50c594536708499d7b1a8 100644 (file)
@@ -62,6 +62,7 @@ obj-y += sysctl.o
 obj-y += time.o
 obj-y += trace.o
 obj-y += traps.o
+obj-y += tsx.o
 obj-y += usercopy.o
 obj-y += x86_emulate.o
 obj-$(CONFIG_TBOOT) += tboot.o
index 5338d20c41f5d172eabd95b1c784e815e9105c1f..85350b33aa678c5b4a4c1c94b76ea4e7c5494c3e 100644 (file)
@@ -3600,9 +3600,22 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx,
     case 0x7:
         if ( count == 0 )
         {
-            /* Fold host's FDP_EXCP_ONLY and NO_FPU_SEL into guest's view. */
-            *ebx &= (hvm_featureset[FEATURESET_7b0] &
-                     ~special_features[FEATURESET_7b0]);
+            /*
+             * Fold host's FDP_EXCP_ONLY and NO_FPU_SEL into guest's view.
+             *
+             * 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.
+             */
+            *ebx &= ((hvm_featureset[FEATURESET_7b0] &
+                      ~special_features[FEATURESET_7b0]) |
+                     (cpu_has_tsx_ctrl ?
+                      (cpufeat_mask(X86_FEATURE_HLE) |
+                       cpufeat_mask(X86_FEATURE_RTM)) : 0));
             *ebx |= (host_featureset[FEATURESET_7b0] &
                      special_features[FEATURESET_7b0]);
 
@@ -3955,6 +3968,7 @@ int hvm_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
     case MSR_FLUSH_CMD:
         /* Write-only */
     case MSR_TSX_FORCE_ABORT:
+    case MSR_TSX_CTRL:
         /* Not offered to guests. */
         goto gp_fault;
 
@@ -4201,6 +4215,7 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content,
     case MSR_ARCH_CAPABILITIES:
         /* Read-only */
     case MSR_TSX_FORCE_ABORT:
+    case MSR_TSX_CTRL:
         /* Not offered to guests. */
         goto gp_fault;
 
index 3a7b36251c8543a333bd4ebf836894a4c873f60c..a3fb9251b58edf6d969f222cb85b1e75c8134490 100644 (file)
@@ -1484,6 +1484,8 @@ void __init noreturn __start_xen(unsigned long mbi_p)
 
     early_microcode_init();
 
+    tsx_init(); /* Needs microcode.  May change HLE/RTM feature bits. */
+
     identify_cpu(&boot_cpu_data);
 
     set_in_cr4(X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT);
index 4c602491ba25b01d6664fe44d266ca158779a836..4a3e080f786f6f0f6eefca8ddcd406a57fabd40b 100644 (file)
@@ -361,6 +361,8 @@ void start_secondary(void *unused)
     if ( boot_cpu_has(X86_FEATURE_IBRSB) )
         wrmsrl(MSR_SPEC_CTRL, default_xen_spec_ctrl);
 
+    tsx_init(); /* Needs microcode.  May change HLE/RTM feature bits. */
+
     smp_callin();
 
     init_percpu_time();
index 3c1c4e2c2d169f007a7dffab990c1406dd5b8ae2..2d5dbcaa3a2e66331bc40b499208440bc1449464 100644 (file)
@@ -1141,9 +1141,22 @@ void pv_cpuid(uint32_t leaf, uint32_t subleaf,
     case 0x00000007:
         if ( subleaf == 0 )
         {
-            /* Fold host's FDP_EXCP_ONLY and NO_FPU_SEL into guest's view. */
-            b &= (pv_featureset[FEATURESET_7b0] &
-                  ~special_features[FEATURESET_7b0]);
+            /*
+             * Fold host's FDP_EXCP_ONLY and NO_FPU_SEL into guest's view.
+             *
+             * 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.
+             */
+            b &= ((pv_featureset[FEATURESET_7b0] &
+                   ~special_features[FEATURESET_7b0]) |
+                  (cpu_has_tsx_ctrl ?
+                   (cpufeat_mask(X86_FEATURE_HLE) |
+                    cpufeat_mask(X86_FEATURE_RTM)) : 0));
             b |= (host_featureset[FEATURESET_7b0] &
                   special_features[FEATURESET_7b0]);
 
@@ -2531,6 +2544,7 @@ static int priv_op_read_msr(unsigned int reg, uint64_t *val,
     case MSR_FLUSH_CMD:
         /* Write-only */
     case MSR_TSX_FORCE_ABORT:
+    case MSR_TSX_CTRL:
         /* Not offered to guests. */
         break;
 
@@ -2762,6 +2776,7 @@ static int priv_op_write_msr(unsigned int reg, uint64_t val,
     case MSR_ARCH_CAPABILITIES:
         /* The MSR is read-only. */
     case MSR_TSX_FORCE_ABORT:
+    case MSR_TSX_CTRL:
         /* Not offered to guests. */
         break;
 
diff --git a/xen/arch/x86/tsx.c b/xen/arch/x86/tsx.c
new file mode 100644 (file)
index 0000000..3a853d3
--- /dev/null
@@ -0,0 +1,74 @@
+#include <xen/init.h>
+#include <asm/msr.h>
+
+/*
+ * Valid values:
+ *   1 => Explicit tsx=1
+ *   0 => Explicit tsx=0
+ *  -1 => Default, implicit tsx=1
+ *
+ * This is arranged such that the bottom bit encodes whether TSX is actually
+ * disabled, while identifying various explicit (>=0) and implicit (<0)
+ * conditions.
+ */
+int8_t __read_mostly opt_tsx = -1;
+int8_t __read_mostly cpu_has_tsx_ctrl = -1;
+
+static int __init parse_tsx(const char *s)
+{
+    int rc = 0, val = parse_bool(s);
+
+    if ( val >= 0 )
+        opt_tsx = val;
+    else
+        rc = -EINVAL;
+
+    return rc;
+}
+custom_param("tsx", parse_tsx);
+
+void tsx_init(void)
+{
+    /*
+     * This function is first called between microcode being loaded, and CPUID
+     * being scanned generally.  Calculate from raw data whether MSR_TSX_CTRL
+     * is available.
+     */
+    if ( unlikely(cpu_has_tsx_ctrl < 0) )
+    {
+        uint64_t caps = 0;
+
+        if ( boot_cpu_data.cpuid_level >= 7 &&
+             (cpuid_count_edx(7, 0) & cpufeat_mask(X86_FEATURE_ARCH_CAPS)) )
+            rdmsrl(MSR_ARCH_CAPABILITIES, caps);
+
+        cpu_has_tsx_ctrl = !!(caps & ARCH_CAPS_TSX_CTRL);
+    }
+
+    if ( cpu_has_tsx_ctrl )
+    {
+        uint64_t val;
+
+        rdmsrl(MSR_TSX_CTRL, val);
+
+        val &= ~(TSX_CTRL_RTM_DISABLE | TSX_CTRL_CPUID_CLEAR);
+        /* Check bottom bit only.  Higher bits are various sentinals. */
+        if ( !(opt_tsx & 1) )
+            val |= TSX_CTRL_RTM_DISABLE | TSX_CTRL_CPUID_CLEAR;
+
+        wrmsrl(MSR_TSX_CTRL, val);
+    }
+    else if ( opt_tsx >= 0 )
+        printk_once(XENLOG_WARNING
+                    "MSR_TSX_CTRL not available - Ignoring tsx= setting\n");
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 0a596f7489733ba40929684774b14da4283c2d25..1982137a333052abbad030d29f48fa6a8e04951d 100644 (file)
@@ -55,6 +55,7 @@
 #define ARCH_CAPS_SSB_NO               (_AC(1, ULL) << 4)
 #define ARCH_CAPS_MDS_NO               (_AC(1, ULL) << 5)
 #define ARCH_CAPS_IF_PSCHANGE_MC_NO    (_AC(1, ULL) << 6)
+#define ARCH_CAPS_TSX_CTRL             (_AC(1, ULL) << 7)
 
 #define MSR_FLUSH_CMD                  0x0000010b
 #define FLUSH_CMD_L1D                  (_AC(1, ULL) << 0)
 #define MSR_TSX_FORCE_ABORT             0x0000010f
 #define TSX_FORCE_ABORT_RTM             (_AC(1, ULL) <<  0)
 
+#define MSR_TSX_CTRL                    0x00000122
+#define TSX_CTRL_RTM_DISABLE            (_AC(1, ULL) <<  0)
+#define TSX_CTRL_CPUID_CLEAR            (_AC(1, ULL) <<  1)
+
 /* Intel MSRs. Some also available on other CPUs */
 #define MSR_IA32_PERFCTR0              0x000000c1
 #define MSR_IA32_A_PERFCTR0            0x000004c1
index a5319e3aaf3f260d9171467518b5e0407f6a3e84..dc3f4f8490f551f38d17d9fc94012f375fc5f610 100644 (file)
@@ -339,6 +339,16 @@ static always_inline unsigned int cpuid_edx(unsigned int op)
     return edx;
 }
 
+static always_inline unsigned int cpuid_count_edx(
+    unsigned int leaf, unsigned int subleaf)
+{
+    unsigned int edx, tmp;
+
+    cpuid_count(leaf, subleaf, &tmp, &tmp, &tmp, &edx);
+
+    return edx;
+}
+
 static inline unsigned long read_cr0(void)
 {
     unsigned long cr0;
@@ -692,6 +702,9 @@ static inline void pv_cpuid_regs(struct cpu_user_regs *regs)
              &regs->_eax, &regs->_ebx, &regs->_ecx, &regs->_edx);
 }
 
+extern int8_t opt_tsx, cpu_has_tsx_ctrl;
+void tsx_init(void);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* __ASM_X86_PROCESSOR_H */
index b9d1c87ffd09beb5a17c830b17c91247f55f51ab..b9d2ef0c79c44175cbfc3d8264dc96d3313ce92d 100644 (file)
@@ -103,6 +103,16 @@ extern int printk_ratelimit(void);
 #define gprintk(lvl, fmt, args...) \
     printk(XENLOG_GUEST lvl "%pv " fmt, current, ## args)
 
+#define printk_once(fmt, args...)               \
+({                                              \
+    static bool __read_mostly once_;            \
+    if ( unlikely(!once_) )                     \
+    {                                           \
+        once_ = true;                           \
+        printk(fmt, ## args);                   \
+    }                                           \
+})
+
 #ifdef NDEBUG
 
 static inline void