[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v3 2/2] x86/spec-ctrl: add support for modifying SSBD via LS_CFG MSR



Adds support for modifying the LS_CFG MSR to enable SSBD on supporting
AMD CPUs.  There needs to be locking logic for family 17h with SMT
enabled since both threads share the same MSR.  Otherwise, a core just
needs to write to the LS_CFG MSR.  For more information see:
https://developer.amd.com/wp-content/resources/124441_AMD64_SpeculativeStoreBypassDisable_Whitepaper_final.pdf

Signed-off-by: Brian Woods <brian.woods@xxxxxxx>
---
 xen/arch/x86/cpu/amd.c            |  13 +--
 xen/arch/x86/smpboot.c            |   3 +
 xen/arch/x86/spec_ctrl.c          | 172 +++++++++++++++++++++++++++++++++++++-
 xen/include/asm-x86/cpufeatures.h |   1 +
 xen/include/asm-x86/spec_ctrl.h   |   2 +
 5 files changed, 181 insertions(+), 10 deletions(-)

diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index 6e65ae7427..e96f14268e 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -601,8 +601,8 @@ static void init_amd(struct cpuinfo_x86 *c)
        }
 
        /*
-        * If the user has explicitly chosen to disable Memory Disambiguation
-        * to mitigiate Speculative Store Bypass, poke the appropriate MSR.
+        * Poke the LS_CFG MSR to see if the mitigation for Speculative
+        * Store Bypass is available.
         */
        if (!ssbd_amd_ls_cfg_mask) {
                int bit = -1;
@@ -615,14 +615,9 @@ static void init_amd(struct cpuinfo_x86 *c)
 
                if (bit >= 0)
                        ssbd_amd_ls_cfg_mask = 1ull << bit;
-       }
 
-       if (ssbd_amd_ls_cfg_mask && !rdmsr_safe(MSR_AMD64_LS_CFG, value)) {
-               ssbd_amd_ls_cfg_av = true;
-               if (opt_ssbd) {
-                       value |= ssbd_amd_ls_cfg_mask;
-                       wrmsr_safe(MSR_AMD64_LS_CFG, value);
-               }
+               if (ssbd_amd_ls_cfg_mask && !rdmsr_safe(MSR_AMD64_LS_CFG, 
value))
+                       ssbd_amd_ls_cfg_av = true;
        }
 
        /* MFENCE stops RDTSC speculation */
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index 7e76cc3d68..b103b46dee 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -376,6 +376,9 @@ void start_secondary(void *unused)
     if ( boot_cpu_has(X86_FEATURE_IBRSB) )
         wrmsrl(MSR_SPEC_CTRL, default_xen_spec_ctrl);
 
+    if ( default_xen_ssbd_amd_ls_cfg_en )
+        ssbd_amd_ls_cfg_set(true);
+
     if ( xen_guest )
         hypervisor_ap_setup();
 
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
index b32c12c6c0..89cc444f56 100644
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -20,6 +20,7 @@
 #include <xen/init.h>
 #include <xen/lib.h>
 #include <xen/warning.h>
+#include <xen/spinlock.h>
 
 #include <asm/microcode.h>
 #include <asm/msr.h>
@@ -58,8 +59,17 @@ paddr_t __read_mostly l1tf_addr_mask, __read_mostly 
l1tf_safe_maddr;
 static bool __initdata cpu_has_bug_l1tf;
 static unsigned int __initdata l1d_maxphysaddr;
 
+/* for SSBD support for AMD via LS_CFG */
+#define SSBD_AMD_MAX_SOCKET 4
+struct ssbd_amd_ls_cfg_smt_status {
+    spinlock_t lock;
+    uint32_t mask;
+} __attribute__ ((aligned (64)));
+bool __read_mostly ssbd_amd_smt_en;
+bool __read_mostly default_xen_ssbd_amd_ls_cfg_en;
 bool ssbd_amd_ls_cfg_av;
 uint64_t __read_mostly ssbd_amd_ls_cfg_mask;
+struct ssbd_amd_ls_cfg_smt_status *ssbd_amd_smt_status[SSBD_AMD_MAX_SOCKET];
 
 static int __init parse_bti(const char *s)
 {
@@ -319,7 +329,7 @@ static void __init print_details(enum ind_thunk thunk, 
uint64_t caps)
            !boot_cpu_has(X86_FEATURE_SSBD)           ? "" :
            (default_xen_spec_ctrl & SPEC_CTRL_SSBD)  ? " SSBD+" : " SSBD-",
            !ssbd_amd_ls_cfg_av                       ? "" :
-           opt_ssbd                                  ? " LS_CFG_SSBD+" : " 
LS_CFG_SSBD-",
+           default_xen_ssbd_amd_ls_cfg_en            ? " LS_CFG_SSBD+" : " 
LS_CFG_SSBD-",
            opt_ibpb                                  ? " IBPB"  : "",
            opt_l1d_flush                             ? " L1D_FLUSH" : "");
 
@@ -725,6 +735,162 @@ static __init int parse_xpti(const char *s)
 }
 custom_param("xpti", parse_xpti);
 
+/*
+ * Enabling SSBD on AMD processers via the LS_CFG MSR
+ *
+ * For family 15h and 16h, there are no SMT enabled processors, so there
+ * is no need for locking, just setting an MSR bit.  For 17h, it depends
+ * if SMT is enabled.  If SMT, are two threads that share a single MSR
+ * so there needs to be a lock and a virtual bit for each thread,
+ * otherwise it's the same as family 15h/16h.
+ */
+
+static void ssbd_amd_ls_cfg_set_nonsmt(bool enable_ssbd)
+{
+    uint64_t ls_cfg, new_ls_cfg;
+
+    rdmsrl(MSR_AMD64_LS_CFG, ls_cfg);
+
+    if ( enable_ssbd )
+        new_ls_cfg = ls_cfg | ssbd_amd_ls_cfg_mask;
+    else
+        new_ls_cfg = ls_cfg & ~ssbd_amd_ls_cfg_mask;
+
+    if ( new_ls_cfg != ls_cfg )
+        wrmsrl(MSR_AMD64_LS_CFG, new_ls_cfg);
+}
+
+static void ssbd_amd_ls_cfg_set_smt(bool enable_ssbd)
+{
+    unsigned socket, core, thread;
+    uint64_t enable_mask;
+    uint64_t ls_cfg;
+    struct ssbd_amd_ls_cfg_smt_status *status;
+    const struct cpuinfo_x86  *c =  &current_cpu_data;
+
+    socket = c->phys_proc_id;
+    core   = c->cpu_core_id;
+    thread = c->apicid & (c->x86_num_siblings - 1);
+    status = ssbd_amd_smt_status[socket] + core;
+    enable_mask = (1ull << thread);
+
+    spin_lock(&status->lock);
+
+    if ( enable_ssbd )
+    {
+        if ( !(status->mask & enable_mask) )
+        {
+            status->mask |= enable_mask;
+            rdmsrl(MSR_AMD64_LS_CFG, ls_cfg);
+            if ( !(ls_cfg & ssbd_amd_ls_cfg_mask) )
+            {
+                ls_cfg |= ssbd_amd_ls_cfg_mask;
+                wrmsrl(MSR_AMD64_LS_CFG, ls_cfg);
+            }
+        }
+    }
+    else
+    {
+        if ( status->mask & enable_mask )
+        {
+            status->mask &= ~enable_mask;
+            rdmsrl(MSR_AMD64_LS_CFG, ls_cfg);
+            if ( (ls_cfg & ssbd_amd_ls_cfg_mask) && (status->mask == 0) )
+            {
+                ls_cfg &= ~ssbd_amd_ls_cfg_mask;
+                wrmsrl(MSR_AMD64_LS_CFG, ls_cfg);
+            }
+        }
+    }
+
+    spin_unlock(&status->lock);
+}
+
+void ssbd_amd_ls_cfg_set(bool enable_ssbd)
+{
+    if ( !boot_cpu_has(X86_FEATURE_SSBD_AMD_LS_CFG) )
+        return;
+
+    ASSERT(ssbd_amd_ls_cfg_mask);
+
+    if ( ssbd_amd_smt_en )
+        ssbd_amd_ls_cfg_set_smt(enable_ssbd);
+    else
+        ssbd_amd_ls_cfg_set_nonsmt(enable_ssbd);
+}
+
+static int __init ssbd_amd_ls_cfg_init(void)
+{
+    unsigned cores_per_socket, threads_per_core;
+    unsigned core, socket;
+    const struct cpuinfo_x86  *c =  &boot_cpu_data;
+
+    if ( !ssbd_amd_ls_cfg_av )
+        return 0;
+
+    ASSERT(ssbd_amd_ls_cfg_mask);
+
+    switch ( c->x86 )
+    {
+    case 0x15:
+    case 0x16:
+        break;
+
+    case 0x17:
+        cores_per_socket = c->x86_max_cores;
+        threads_per_core = c->x86_num_siblings;
+
+        if ( threads_per_core > 1 )
+        {
+            ssbd_amd_smt_en = true;
+            for ( socket = 0; socket < nr_sockets; socket++ )
+            {
+                ssbd_amd_smt_status[socket] =
+                  (struct ssbd_amd_ls_cfg_smt_status *)
+                  xmalloc_array(struct ssbd_amd_ls_cfg_smt_status,
+                                cores_per_socket);
+                if ( ssbd_amd_smt_status[socket] == NULL )
+                {
+                    dprintk(XENLOG_ERR,
+                            "SSBD AMD LS CFG: error in status allocing\n");
+                    goto ssbd_amd_ls_cfg_init_fail;
+                }
+            }
+
+            for ( socket = 0; socket < nr_sockets; socket++ )
+            {
+                for ( core = 0; core < cores_per_socket; core++ )
+                {
+                    spin_lock_init(&ssbd_amd_smt_status[socket][core].lock);
+                    ssbd_amd_smt_status[socket][core].mask = 0;
+                }
+            }
+        }
+        break;
+
+    default:
+        goto ssbd_amd_ls_cfg_init_fail;
+    }
+
+    setup_force_cpu_cap(X86_FEATURE_SSBD_AMD_LS_CFG);
+
+    if ( default_xen_ssbd_amd_ls_cfg_en )
+        ssbd_amd_ls_cfg_set(true);
+
+    return 0;
+
+ ssbd_amd_ls_cfg_init_fail:
+    for ( socket = 0; socket < SSBD_AMD_MAX_SOCKET; socket++ )
+        xfree(ssbd_amd_smt_status[socket]);
+
+    default_xen_ssbd_amd_ls_cfg_en = false;
+
+    dprintk(XENLOG_ERR, "SSBD AMD LS CFG: disalbing SSBD due to errors\n");
+
+    return 0;
+}
+presmp_initcall(ssbd_amd_ls_cfg_init);
+
 void __init init_speculation_mitigations(void)
 {
     enum ind_thunk thunk = THUNK_DEFAULT;
@@ -827,6 +993,10 @@ void __init init_speculation_mitigations(void)
     if ( boot_cpu_has(X86_FEATURE_SSBD) && opt_ssbd )
         default_xen_spec_ctrl |= SPEC_CTRL_SSBD;
 
+    /* if we have SSBD LS_CFG available, see whether we should use it. */
+    if ( ssbd_amd_ls_cfg_av && opt_ssbd )
+         default_xen_ssbd_amd_ls_cfg_en = true;
+
     /*
      * PV guests can poison the RSB to any virtual address from which
      * they can execute a call instruction.  This is necessarily outside
diff --git a/xen/include/asm-x86/cpufeatures.h 
b/xen/include/asm-x86/cpufeatures.h
index 249fa6e531..8927704ef3 100644
--- a/xen/include/asm-x86/cpufeatures.h
+++ b/xen/include/asm-x86/cpufeatures.h
@@ -33,3 +33,4 @@ XEN_CPUFEATURE(SC_RSB_HVM,      (FSCAPINTS+0)*32+19) /* RSB 
overwrite needed for
 XEN_CPUFEATURE(NO_XPTI,         (FSCAPINTS+0)*32+20) /* XPTI mitigation not in 
use */
 XEN_CPUFEATURE(SC_MSR_IDLE,     (FSCAPINTS+0)*32+21) /* (SC_MSR_PV || 
SC_MSR_HVM) && default_xen_spec_ctrl */
 XEN_CPUFEATURE(XEN_LBR,         (FSCAPINTS+0)*32+22) /* Xen uses 
MSR_DEBUGCTL.LBR */
+XEN_CPUFEATURE(SSBD_AMD_LS_CFG, (FSCAPINTS+0)*32+23) /* if SSBD support is 
enabled via LS    _CGF MSR on AMD hardware */
diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h
index 1b9101a988..b142cf09d7 100644
--- a/xen/include/asm-x86/spec_ctrl.h
+++ b/xen/include/asm-x86/spec_ctrl.h
@@ -52,6 +52,8 @@ extern paddr_t l1tf_addr_mask, l1tf_safe_maddr;
 
 extern bool ssbd_amd_ls_cfg_av;
 extern uint64_t ssbd_amd_ls_cfg_mask;
+extern bool default_xen_ssbd_amd_ls_cfg_en;
+extern void ssbd_amd_ls_cfg_set(bool enable_ssbd);
 
 static inline void init_shadow_spec_ctrl_state(void)
 {
-- 
2.11.0


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.