]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - arch/x86/kernel/cpu/bugs.c
KVM: VMX: Prevent RSB underflow before vmenter
[mirror_ubuntu-jammy-kernel.git] / arch / x86 / kernel / cpu / bugs.c
index ecfca3bbcd96866c8666accd32947656b10f7159..8bc493c72e05eb764972cacc24cf2ffc3053abf9 100644 (file)
 #include <linux/prctl.h>
 #include <linux/sched/smt.h>
 #include <linux/pgtable.h>
+#include <linux/bpf.h>
 
 #include <asm/spec-ctrl.h>
 #include <asm/cmdline.h>
 #include <asm/bugs.h>
 #include <asm/processor.h>
 #include <asm/processor-flags.h>
-#include <asm/fpu/internal.h>
+#include <asm/fpu/api.h>
 #include <asm/msr.h>
 #include <asm/vmx.h>
 #include <asm/paravirt.h>
 
 static void __init spectre_v1_select_mitigation(void);
 static void __init spectre_v2_select_mitigation(void);
+static void __init retbleed_select_mitigation(void);
+static void __init spectre_v2_user_select_mitigation(void);
 static void __init ssb_select_mitigation(void);
 static void __init l1tf_select_mitigation(void);
 static void __init mds_select_mitigation(void);
-static void __init mds_print_mitigation(void);
+static void __init md_clear_update_mitigation(void);
+static void __init md_clear_select_mitigation(void);
 static void __init taa_select_mitigation(void);
+static void __init mmio_select_mitigation(void);
 static void __init srbds_select_mitigation(void);
 static void __init l1d_flush_select_mitigation(void);
 
-/* The base value of the SPEC_CTRL MSR that always has to be preserved. */
+/* The base value of the SPEC_CTRL MSR without task-specific bits set */
 u64 x86_spec_ctrl_base;
 EXPORT_SYMBOL_GPL(x86_spec_ctrl_base);
+
+/* The current value of the SPEC_CTRL MSR with task-specific bits set */
+DEFINE_PER_CPU(u64, x86_spec_ctrl_current);
+EXPORT_SYMBOL_GPL(x86_spec_ctrl_current);
+
 static DEFINE_MUTEX(spec_ctrl_mutex);
 
 /*
- * The vendor and possibly platform specific bits which can be modified in
- * x86_spec_ctrl_base.
+ * Keep track of the SPEC_CTRL MSR value for the current task, which may differ
+ * from x86_spec_ctrl_base due to STIBP/SSB in __speculation_ctrl_update().
  */
-static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS;
+void write_spec_ctrl_current(u64 val, bool force)
+{
+       if (this_cpu_read(x86_spec_ctrl_current) == val)
+               return;
+
+       this_cpu_write(x86_spec_ctrl_current, val);
+
+       /*
+        * When KERNEL_IBRS this MSR is written on return-to-user, unless
+        * forced the update can be delayed until that time.
+        */
+       if (force || !cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS))
+               wrmsrl(MSR_IA32_SPEC_CTRL, val);
+}
+
+u64 spec_ctrl_current(void)
+{
+       return this_cpu_read(x86_spec_ctrl_current);
+}
+EXPORT_SYMBOL_GPL(spec_ctrl_current);
 
 /*
  * AMD specific MSR info for Speculative Store Bypass control.
@@ -84,6 +113,10 @@ EXPORT_SYMBOL_GPL(mds_idle_clear);
  */
 DEFINE_STATIC_KEY_FALSE(switch_mm_cond_l1d_flush);
 
+/* Controls CPU Fill buffer clear before KVM guest MMIO accesses */
+DEFINE_STATIC_KEY_FALSE(mmio_stale_data_clear);
+EXPORT_SYMBOL_GPL(mmio_stale_data_clear);
+
 void __init check_bugs(void)
 {
        identify_boot_cpu();
@@ -107,26 +140,27 @@ void __init check_bugs(void)
        if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
                rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
 
-       /* Allow STIBP in MSR_SPEC_CTRL if supported */
-       if (boot_cpu_has(X86_FEATURE_STIBP))
-               x86_spec_ctrl_mask |= SPEC_CTRL_STIBP;
-
        /* Select the proper CPU mitigations before patching alternatives: */
        spectre_v1_select_mitigation();
        spectre_v2_select_mitigation();
+       /*
+        * retbleed_select_mitigation() relies on the state set by
+        * spectre_v2_select_mitigation(); specifically it wants to know about
+        * spectre_v2=ibrs.
+        */
+       retbleed_select_mitigation();
+       /*
+        * spectre_v2_user_select_mitigation() relies on the state set by
+        * retbleed_select_mitigation(); specifically the STIBP selection is
+        * forced for UNRET.
+        */
+       spectre_v2_user_select_mitigation();
        ssb_select_mitigation();
        l1tf_select_mitigation();
-       mds_select_mitigation();
-       taa_select_mitigation();
+       md_clear_select_mitigation();
        srbds_select_mitigation();
        l1d_flush_select_mitigation();
 
-       /*
-        * As MDS and TAA mitigations are inter-related, print MDS
-        * mitigation until after TAA mitigation selection is done.
-        */
-       mds_print_mitigation();
-
        arch_smt_update();
 
 #ifdef CONFIG_X86_32
@@ -161,31 +195,17 @@ void __init check_bugs(void)
 #endif
 }
 
+/*
+ * NOTE: This function is *only* called for SVM.  VMX spec_ctrl handling is
+ * done in vmenter.S.
+ */
 void
 x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest)
 {
-       u64 msrval, guestval, hostval = x86_spec_ctrl_base;
+       u64 msrval, guestval = guest_spec_ctrl, hostval = spec_ctrl_current();
        struct thread_info *ti = current_thread_info();
 
-       /* Is MSR_SPEC_CTRL implemented ? */
        if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) {
-               /*
-                * Restrict guest_spec_ctrl to supported values. Clear the
-                * modifiable bits in the host base value and or the
-                * modifiable bits from the guest value.
-                */
-               guestval = hostval & ~x86_spec_ctrl_mask;
-               guestval |= guest_spec_ctrl & x86_spec_ctrl_mask;
-
-               /* SSBD controlled in MSR_SPEC_CTRL */
-               if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-                   static_cpu_has(X86_FEATURE_AMD_SSBD))
-                       hostval |= ssbd_tif_to_spec_ctrl(ti->flags);
-
-               /* Conditional STIBP enabled? */
-               if (static_branch_unlikely(&switch_to_cond_stibp))
-                       hostval |= stibp_tif_to_spec_ctrl(ti->flags);
-
                if (hostval != guestval) {
                        msrval = setguest ? guestval : hostval;
                        wrmsrl(MSR_IA32_SPEC_CTRL, msrval);
@@ -266,14 +286,6 @@ static void __init mds_select_mitigation(void)
        }
 }
 
-static void __init mds_print_mitigation(void)
-{
-       if (!boot_cpu_has_bug(X86_BUG_MDS) || cpu_mitigations_off())
-               return;
-
-       pr_info("%s\n", mds_strings[mds_mitigation]);
-}
-
 static int __init mds_cmdline(char *str)
 {
        if (!boot_cpu_has_bug(X86_BUG_MDS))
@@ -328,7 +340,7 @@ static void __init taa_select_mitigation(void)
        /* TSX previously disabled by tsx=off */
        if (!boot_cpu_has(X86_FEATURE_RTM)) {
                taa_mitigation = TAA_MITIGATION_TSX_DISABLED;
-               goto out;
+               return;
        }
 
        if (cpu_mitigations_off()) {
@@ -342,7 +354,7 @@ static void __init taa_select_mitigation(void)
         */
        if (taa_mitigation == TAA_MITIGATION_OFF &&
            mds_mitigation == MDS_MITIGATION_OFF)
-               goto out;
+               return;
 
        if (boot_cpu_has(X86_FEATURE_MD_CLEAR))
                taa_mitigation = TAA_MITIGATION_VERW;
@@ -374,18 +386,6 @@ static void __init taa_select_mitigation(void)
 
        if (taa_nosmt || cpu_mitigations_auto_nosmt())
                cpu_smt_disable(false);
-
-       /*
-        * Update MDS mitigation, if necessary, as the mds_user_clear is
-        * now enabled for TAA mitigation.
-        */
-       if (mds_mitigation == MDS_MITIGATION_OFF &&
-           boot_cpu_has_bug(X86_BUG_MDS)) {
-               mds_mitigation = MDS_MITIGATION_FULL;
-               mds_select_mitigation();
-       }
-out:
-       pr_info("%s\n", taa_strings[taa_mitigation]);
 }
 
 static int __init tsx_async_abort_parse_cmdline(char *str)
@@ -409,6 +409,151 @@ static int __init tsx_async_abort_parse_cmdline(char *str)
 }
 early_param("tsx_async_abort", tsx_async_abort_parse_cmdline);
 
+#undef pr_fmt
+#define pr_fmt(fmt)    "MMIO Stale Data: " fmt
+
+enum mmio_mitigations {
+       MMIO_MITIGATION_OFF,
+       MMIO_MITIGATION_UCODE_NEEDED,
+       MMIO_MITIGATION_VERW,
+};
+
+/* Default mitigation for Processor MMIO Stale Data vulnerabilities */
+static enum mmio_mitigations mmio_mitigation __ro_after_init = MMIO_MITIGATION_VERW;
+static bool mmio_nosmt __ro_after_init = false;
+
+static const char * const mmio_strings[] = {
+       [MMIO_MITIGATION_OFF]           = "Vulnerable",
+       [MMIO_MITIGATION_UCODE_NEEDED]  = "Vulnerable: Clear CPU buffers attempted, no microcode",
+       [MMIO_MITIGATION_VERW]          = "Mitigation: Clear CPU buffers",
+};
+
+static void __init mmio_select_mitigation(void)
+{
+       u64 ia32_cap;
+
+       if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA) ||
+           cpu_mitigations_off()) {
+               mmio_mitigation = MMIO_MITIGATION_OFF;
+               return;
+       }
+
+       if (mmio_mitigation == MMIO_MITIGATION_OFF)
+               return;
+
+       ia32_cap = x86_read_arch_cap_msr();
+
+       /*
+        * Enable CPU buffer clear mitigation for host and VMM, if also affected
+        * by MDS or TAA. Otherwise, enable mitigation for VMM only.
+        */
+       if (boot_cpu_has_bug(X86_BUG_MDS) || (boot_cpu_has_bug(X86_BUG_TAA) &&
+                                             boot_cpu_has(X86_FEATURE_RTM)))
+               static_branch_enable(&mds_user_clear);
+       else
+               static_branch_enable(&mmio_stale_data_clear);
+
+       /*
+        * If Processor-MMIO-Stale-Data bug is present and Fill Buffer data can
+        * be propagated to uncore buffers, clearing the Fill buffers on idle
+        * is required irrespective of SMT state.
+        */
+       if (!(ia32_cap & ARCH_CAP_FBSDP_NO))
+               static_branch_enable(&mds_idle_clear);
+
+       /*
+        * Check if the system has the right microcode.
+        *
+        * CPU Fill buffer clear mitigation is enumerated by either an explicit
+        * FB_CLEAR or by the presence of both MD_CLEAR and L1D_FLUSH on MDS
+        * affected systems.
+        */
+       if ((ia32_cap & ARCH_CAP_FB_CLEAR) ||
+           (boot_cpu_has(X86_FEATURE_MD_CLEAR) &&
+            boot_cpu_has(X86_FEATURE_FLUSH_L1D) &&
+            !(ia32_cap & ARCH_CAP_MDS_NO)))
+               mmio_mitigation = MMIO_MITIGATION_VERW;
+       else
+               mmio_mitigation = MMIO_MITIGATION_UCODE_NEEDED;
+
+       if (mmio_nosmt || cpu_mitigations_auto_nosmt())
+               cpu_smt_disable(false);
+}
+
+static int __init mmio_stale_data_parse_cmdline(char *str)
+{
+       if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
+               return 0;
+
+       if (!str)
+               return -EINVAL;
+
+       if (!strcmp(str, "off")) {
+               mmio_mitigation = MMIO_MITIGATION_OFF;
+       } else if (!strcmp(str, "full")) {
+               mmio_mitigation = MMIO_MITIGATION_VERW;
+       } else if (!strcmp(str, "full,nosmt")) {
+               mmio_mitigation = MMIO_MITIGATION_VERW;
+               mmio_nosmt = true;
+       }
+
+       return 0;
+}
+early_param("mmio_stale_data", mmio_stale_data_parse_cmdline);
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "" fmt
+
+static void __init md_clear_update_mitigation(void)
+{
+       if (cpu_mitigations_off())
+               return;
+
+       if (!static_key_enabled(&mds_user_clear))
+               goto out;
+
+       /*
+        * mds_user_clear is now enabled. Update MDS, TAA and MMIO Stale Data
+        * mitigation, if necessary.
+        */
+       if (mds_mitigation == MDS_MITIGATION_OFF &&
+           boot_cpu_has_bug(X86_BUG_MDS)) {
+               mds_mitigation = MDS_MITIGATION_FULL;
+               mds_select_mitigation();
+       }
+       if (taa_mitigation == TAA_MITIGATION_OFF &&
+           boot_cpu_has_bug(X86_BUG_TAA)) {
+               taa_mitigation = TAA_MITIGATION_VERW;
+               taa_select_mitigation();
+       }
+       if (mmio_mitigation == MMIO_MITIGATION_OFF &&
+           boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) {
+               mmio_mitigation = MMIO_MITIGATION_VERW;
+               mmio_select_mitigation();
+       }
+out:
+       if (boot_cpu_has_bug(X86_BUG_MDS))
+               pr_info("MDS: %s\n", mds_strings[mds_mitigation]);
+       if (boot_cpu_has_bug(X86_BUG_TAA))
+               pr_info("TAA: %s\n", taa_strings[taa_mitigation]);
+       if (boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
+               pr_info("MMIO Stale Data: %s\n", mmio_strings[mmio_mitigation]);
+}
+
+static void __init md_clear_select_mitigation(void)
+{
+       mds_select_mitigation();
+       taa_select_mitigation();
+       mmio_select_mitigation();
+
+       /*
+        * As MDS, TAA and MMIO Stale Data mitigations are inter-related, update
+        * and print their mitigation after MDS, TAA and MMIO Stale Data
+        * mitigation selection is done.
+        */
+       md_clear_update_mitigation();
+}
+
 #undef pr_fmt
 #define pr_fmt(fmt)    "SRBDS: " fmt
 
@@ -470,11 +615,13 @@ static void __init srbds_select_mitigation(void)
                return;
 
        /*
-        * Check to see if this is one of the MDS_NO systems supporting
-        * TSX that are only exposed to SRBDS when TSX is enabled.
+        * Check to see if this is one of the MDS_NO systems supporting TSX that
+        * are only exposed to SRBDS when TSX is enabled or when CPU is affected
+        * by Processor MMIO Stale Data vulnerability.
         */
        ia32_cap = x86_read_arch_cap_msr();
-       if ((ia32_cap & ARCH_CAP_MDS_NO) && !boot_cpu_has(X86_FEATURE_RTM))
+       if ((ia32_cap & ARCH_CAP_MDS_NO) && !boot_cpu_has(X86_FEATURE_RTM) &&
+           !boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
                srbds_mitigation = SRBDS_MITIGATION_TSX_OFF;
        else if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
                srbds_mitigation = SRBDS_MITIGATION_HYPERVISOR;
@@ -618,12 +765,172 @@ static int __init nospectre_v1_cmdline(char *str)
 }
 early_param("nospectre_v1", nospectre_v1_cmdline);
 
-#undef pr_fmt
-#define pr_fmt(fmt)     "Spectre V2 : " fmt
-
 static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
        SPECTRE_V2_NONE;
 
+#undef pr_fmt
+#define pr_fmt(fmt)     "RETBleed: " fmt
+
+enum retbleed_mitigation {
+       RETBLEED_MITIGATION_NONE,
+       RETBLEED_MITIGATION_UNRET,
+       RETBLEED_MITIGATION_IBPB,
+       RETBLEED_MITIGATION_IBRS,
+       RETBLEED_MITIGATION_EIBRS,
+};
+
+enum retbleed_mitigation_cmd {
+       RETBLEED_CMD_OFF,
+       RETBLEED_CMD_AUTO,
+       RETBLEED_CMD_UNRET,
+       RETBLEED_CMD_IBPB,
+};
+
+const char * const retbleed_strings[] = {
+       [RETBLEED_MITIGATION_NONE]      = "Vulnerable",
+       [RETBLEED_MITIGATION_UNRET]     = "Mitigation: untrained return thunk",
+       [RETBLEED_MITIGATION_IBPB]      = "Mitigation: IBPB",
+       [RETBLEED_MITIGATION_IBRS]      = "Mitigation: IBRS",
+       [RETBLEED_MITIGATION_EIBRS]     = "Mitigation: Enhanced IBRS",
+};
+
+static enum retbleed_mitigation retbleed_mitigation __ro_after_init =
+       RETBLEED_MITIGATION_NONE;
+static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init =
+       RETBLEED_CMD_AUTO;
+
+static int __ro_after_init retbleed_nosmt = false;
+
+static int __init retbleed_parse_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       while (str) {
+               char *next = strchr(str, ',');
+               if (next) {
+                       *next = 0;
+                       next++;
+               }
+
+               if (!strcmp(str, "off")) {
+                       retbleed_cmd = RETBLEED_CMD_OFF;
+               } else if (!strcmp(str, "auto")) {
+                       retbleed_cmd = RETBLEED_CMD_AUTO;
+               } else if (!strcmp(str, "unret")) {
+                       retbleed_cmd = RETBLEED_CMD_UNRET;
+               } else if (!strcmp(str, "ibpb")) {
+                       retbleed_cmd = RETBLEED_CMD_IBPB;
+               } else if (!strcmp(str, "nosmt")) {
+                       retbleed_nosmt = true;
+               } else {
+                       pr_err("Ignoring unknown retbleed option (%s).", str);
+               }
+
+               str = next;
+       }
+
+       return 0;
+}
+early_param("retbleed", retbleed_parse_cmdline);
+
+#define RETBLEED_UNTRAIN_MSG "WARNING: BTB untrained return thunk mitigation is only effective on AMD/Hygon!\n"
+#define RETBLEED_COMPILER_MSG "WARNING: kernel not compiled with RETPOLINE or -mfunction-return capable compiler; falling back to IBPB!\n"
+#define RETBLEED_INTEL_MSG "WARNING: Spectre v2 mitigation leaves CPU vulnerable to RETBleed attacks, data leaks possible!\n"
+
+static void __init retbleed_select_mitigation(void)
+{
+       bool mitigate_smt = false;
+
+       if (!boot_cpu_has_bug(X86_BUG_RETBLEED) || cpu_mitigations_off())
+               return;
+
+       switch (retbleed_cmd) {
+       case RETBLEED_CMD_OFF:
+               return;
+
+       case RETBLEED_CMD_UNRET:
+               retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
+               break;
+
+       case RETBLEED_CMD_IBPB:
+               retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
+               break;
+
+       case RETBLEED_CMD_AUTO:
+       default:
+               if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
+                   boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
+                       retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
+
+               /*
+                * The Intel mitigation (IBRS or eIBRS) was already selected in
+                * spectre_v2_select_mitigation().  'retbleed_mitigation' will
+                * be set accordingly below.
+                */
+
+               break;
+       }
+
+       switch (retbleed_mitigation) {
+       case RETBLEED_MITIGATION_UNRET:
+
+               if (!IS_ENABLED(CONFIG_RETPOLINE) ||
+                   !IS_ENABLED(CONFIG_CC_HAS_RETURN_THUNK)) {
+                       pr_err(RETBLEED_COMPILER_MSG);
+                       retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
+                       goto retbleed_force_ibpb;
+               }
+
+               setup_force_cpu_cap(X86_FEATURE_RETHUNK);
+               setup_force_cpu_cap(X86_FEATURE_UNRET);
+
+               if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+                   boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                       pr_err(RETBLEED_UNTRAIN_MSG);
+
+               mitigate_smt = true;
+               break;
+
+       case RETBLEED_MITIGATION_IBPB:
+retbleed_force_ibpb:
+               setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
+               mitigate_smt = true;
+               break;
+
+       default:
+               break;
+       }
+
+       if (mitigate_smt && !boot_cpu_has(X86_FEATURE_STIBP) &&
+           (retbleed_nosmt || cpu_mitigations_auto_nosmt()))
+               cpu_smt_disable(false);
+
+       /*
+        * Let IBRS trump all on Intel without affecting the effects of the
+        * retbleed= cmdline option.
+        */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+               switch (spectre_v2_enabled) {
+               case SPECTRE_V2_IBRS:
+                       retbleed_mitigation = RETBLEED_MITIGATION_IBRS;
+                       break;
+               case SPECTRE_V2_EIBRS:
+               case SPECTRE_V2_EIBRS_RETPOLINE:
+               case SPECTRE_V2_EIBRS_LFENCE:
+                       retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
+                       break;
+               default:
+                       pr_err(RETBLEED_INTEL_MSG);
+               }
+       }
+
+       pr_info("%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Spectre V2 : " fmt
+
 static enum spectre_v2_user_mitigation spectre_v2_user_stibp __ro_after_init =
        SPECTRE_V2_USER_NONE;
 static enum spectre_v2_user_mitigation spectre_v2_user_ibpb __ro_after_init =
@@ -650,6 +957,32 @@ static inline const char *spectre_v2_module_string(void)
 static inline const char *spectre_v2_module_string(void) { return ""; }
 #endif
 
+#define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n"
+#define SPECTRE_V2_EIBRS_EBPF_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS on, data leaks possible via Spectre v2 BHB attacks!\n"
+#define SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS+LFENCE mitigation and SMT, data leaks possible via Spectre v2 BHB attacks!\n"
+
+#ifdef CONFIG_BPF_SYSCALL
+void unpriv_ebpf_notify(int new_state)
+{
+       if (new_state)
+               return;
+
+       /* Unprivileged eBPF is enabled */
+
+       switch (spectre_v2_enabled) {
+       case SPECTRE_V2_EIBRS:
+               pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
+               break;
+       case SPECTRE_V2_EIBRS_LFENCE:
+               if (sched_smt_active())
+                       pr_err(SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG);
+               break;
+       default:
+               break;
+       }
+}
+#endif
+
 static inline bool match_option(const char *arg, int arglen, const char *opt)
 {
        int len = strlen(opt);
@@ -664,7 +997,11 @@ enum spectre_v2_mitigation_cmd {
        SPECTRE_V2_CMD_FORCE,
        SPECTRE_V2_CMD_RETPOLINE,
        SPECTRE_V2_CMD_RETPOLINE_GENERIC,
-       SPECTRE_V2_CMD_RETPOLINE_AMD,
+       SPECTRE_V2_CMD_RETPOLINE_LFENCE,
+       SPECTRE_V2_CMD_EIBRS,
+       SPECTRE_V2_CMD_EIBRS_RETPOLINE,
+       SPECTRE_V2_CMD_EIBRS_LFENCE,
+       SPECTRE_V2_CMD_IBRS,
 };
 
 enum spectre_v2_user_cmd {
@@ -705,13 +1042,15 @@ static void __init spec_v2_user_print_cond(const char *reason, bool secure)
                pr_info("spectre_v2_user=%s forced on command line.\n", reason);
 }
 
+static __ro_after_init enum spectre_v2_mitigation_cmd spectre_v2_cmd;
+
 static enum spectre_v2_user_cmd __init
-spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_parse_user_cmdline(void)
 {
        char arg[20];
        int ret, i;
 
-       switch (v2_cmd) {
+       switch (spectre_v2_cmd) {
        case SPECTRE_V2_CMD_NONE:
                return SPECTRE_V2_USER_CMD_NONE;
        case SPECTRE_V2_CMD_FORCE:
@@ -737,8 +1076,16 @@ spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
        return SPECTRE_V2_USER_CMD_AUTO;
 }
 
+static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
+{
+       return mode == SPECTRE_V2_IBRS ||
+              mode == SPECTRE_V2_EIBRS ||
+              mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+              mode == SPECTRE_V2_EIBRS_LFENCE;
+}
+
 static void __init
-spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_user_select_mitigation(void)
 {
        enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE;
        bool smt_possible = IS_ENABLED(CONFIG_SMP);
@@ -751,7 +1098,7 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
                smt_possible = false;
 
-       cmd = spectre_v2_parse_user_cmdline(v2_cmd);
+       cmd = spectre_v2_parse_user_cmdline();
        switch (cmd) {
        case SPECTRE_V2_USER_CMD_NONE:
                goto set_mode;
@@ -799,12 +1146,12 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
        }
 
        /*
-        * If no STIBP, enhanced IBRS is enabled or SMT impossible, STIBP is not
-        * required.
+        * If no STIBP, IBRS or enhanced IBRS is enabled, or SMT impossible,
+        * STIBP is not required.
         */
        if (!boot_cpu_has(X86_FEATURE_STIBP) ||
            !smt_possible ||
-           spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
+           spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return;
 
        /*
@@ -816,6 +1163,13 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
                mode = SPECTRE_V2_USER_STRICT_PREFERRED;
 
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+               if (mode != SPECTRE_V2_USER_STRICT &&
+                   mode != SPECTRE_V2_USER_STRICT_PREFERRED)
+                       pr_info("Selecting STIBP always-on mode to complement retbleed mitigation'\n");
+               mode = SPECTRE_V2_USER_STRICT_PREFERRED;
+       }
+
        spectre_v2_user_stibp = mode;
 
 set_mode:
@@ -824,9 +1178,12 @@ set_mode:
 
 static const char * const spectre_v2_strings[] = {
        [SPECTRE_V2_NONE]                       = "Vulnerable",
-       [SPECTRE_V2_RETPOLINE_GENERIC]          = "Mitigation: Full generic retpoline",
-       [SPECTRE_V2_RETPOLINE_AMD]              = "Mitigation: Full AMD retpoline",
-       [SPECTRE_V2_IBRS_ENHANCED]              = "Mitigation: Enhanced IBRS",
+       [SPECTRE_V2_RETPOLINE]                  = "Mitigation: Retpolines",
+       [SPECTRE_V2_LFENCE]                     = "Mitigation: LFENCE",
+       [SPECTRE_V2_EIBRS]                      = "Mitigation: Enhanced IBRS",
+       [SPECTRE_V2_EIBRS_LFENCE]               = "Mitigation: Enhanced IBRS + LFENCE",
+       [SPECTRE_V2_EIBRS_RETPOLINE]            = "Mitigation: Enhanced IBRS + Retpolines",
+       [SPECTRE_V2_IBRS]                       = "Mitigation: IBRS",
 };
 
 static const struct {
@@ -837,9 +1194,14 @@ static const struct {
        { "off",                SPECTRE_V2_CMD_NONE,              false },
        { "on",                 SPECTRE_V2_CMD_FORCE,             true  },
        { "retpoline",          SPECTRE_V2_CMD_RETPOLINE,         false },
-       { "retpoline,amd",      SPECTRE_V2_CMD_RETPOLINE_AMD,     false },
+       { "retpoline,amd",      SPECTRE_V2_CMD_RETPOLINE_LFENCE,  false },
+       { "retpoline,lfence",   SPECTRE_V2_CMD_RETPOLINE_LFENCE,  false },
        { "retpoline,generic",  SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
+       { "eibrs",              SPECTRE_V2_CMD_EIBRS,             false },
+       { "eibrs,lfence",       SPECTRE_V2_CMD_EIBRS_LFENCE,      false },
+       { "eibrs,retpoline",    SPECTRE_V2_CMD_EIBRS_RETPOLINE,   false },
        { "auto",               SPECTRE_V2_CMD_AUTO,              false },
+       { "ibrs",               SPECTRE_V2_CMD_IBRS,              false },
 };
 
 static void __init spec_v2_print_cond(const char *reason, bool secure)
@@ -875,17 +1237,48 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
        }
 
        if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
-            cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
-            cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
+            cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
+            cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC ||
+            cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
+            cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
            !IS_ENABLED(CONFIG_RETPOLINE)) {
-               pr_err("%s selected but not compiled in. Switching to AUTO select\n", mitigation_options[i].option);
+               pr_err("%s selected but not compiled in. Switching to AUTO select\n",
+                      mitigation_options[i].option);
                return SPECTRE_V2_CMD_AUTO;
        }
 
-       if (cmd == SPECTRE_V2_CMD_RETPOLINE_AMD &&
-           boot_cpu_data.x86_vendor != X86_VENDOR_HYGON &&
-           boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
-               pr_err("retpoline,amd selected but CPU is not AMD. Switching to AUTO select\n");
+       if ((cmd == SPECTRE_V2_CMD_EIBRS ||
+            cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
+            cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
+           !boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
+               pr_err("%s selected but CPU doesn't have eIBRS. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if ((cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
+            cmd == SPECTRE_V2_CMD_EIBRS_LFENCE) &&
+           !boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
+               pr_err("%s selected, but CPU doesn't have a serializing LFENCE. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
+               pr_err("%s selected but not Intel CPU. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && !boot_cpu_has(X86_FEATURE_IBRS)) {
+               pr_err("%s selected but CPU doesn't have IBRS. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_has(X86_FEATURE_XENPV)) {
+               pr_err("%s selected but running as XenPV guest. Switching to AUTO select\n",
+                      mitigation_options[i].option);
                return SPECTRE_V2_CMD_AUTO;
        }
 
@@ -894,6 +1287,16 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
        return cmd;
 }
 
+static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
+{
+       if (!IS_ENABLED(CONFIG_RETPOLINE)) {
+               pr_err("Kernel not compiled with retpoline; no mitigation available!");
+               return SPECTRE_V2_NONE;
+       }
+
+       return SPECTRE_V2_RETPOLINE;
+}
+
 static void __init spectre_v2_select_mitigation(void)
 {
        enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
@@ -914,86 +1317,170 @@ static void __init spectre_v2_select_mitigation(void)
        case SPECTRE_V2_CMD_FORCE:
        case SPECTRE_V2_CMD_AUTO:
                if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
-                       mode = SPECTRE_V2_IBRS_ENHANCED;
-                       /* Force it so VMEXIT will restore correctly */
-                       x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
-                       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
-                       goto specv2_set_mode;
+                       mode = SPECTRE_V2_EIBRS;
+                       break;
+               }
+
+               if (boot_cpu_has_bug(X86_BUG_RETBLEED) &&
+                   retbleed_cmd != RETBLEED_CMD_OFF &&
+                   boot_cpu_has(X86_FEATURE_IBRS) &&
+                   boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+                       mode = SPECTRE_V2_IBRS;
+                       break;
                }
-               if (IS_ENABLED(CONFIG_RETPOLINE))
-                       goto retpoline_auto;
+
+               mode = spectre_v2_select_retpoline();
                break;
-       case SPECTRE_V2_CMD_RETPOLINE_AMD:
-               if (IS_ENABLED(CONFIG_RETPOLINE))
-                       goto retpoline_amd;
+
+       case SPECTRE_V2_CMD_RETPOLINE_LFENCE:
+               pr_err(SPECTRE_V2_LFENCE_MSG);
+               mode = SPECTRE_V2_LFENCE;
                break;
+
        case SPECTRE_V2_CMD_RETPOLINE_GENERIC:
-               if (IS_ENABLED(CONFIG_RETPOLINE))
-                       goto retpoline_generic;
+               mode = SPECTRE_V2_RETPOLINE;
                break;
+
        case SPECTRE_V2_CMD_RETPOLINE:
-               if (IS_ENABLED(CONFIG_RETPOLINE))
-                       goto retpoline_auto;
+               mode = spectre_v2_select_retpoline();
+               break;
+
+       case SPECTRE_V2_CMD_IBRS:
+               mode = SPECTRE_V2_IBRS;
+               break;
+
+       case SPECTRE_V2_CMD_EIBRS:
+               mode = SPECTRE_V2_EIBRS;
+               break;
+
+       case SPECTRE_V2_CMD_EIBRS_LFENCE:
+               mode = SPECTRE_V2_EIBRS_LFENCE;
+               break;
+
+       case SPECTRE_V2_CMD_EIBRS_RETPOLINE:
+               mode = SPECTRE_V2_EIBRS_RETPOLINE;
                break;
        }
-       pr_err("Spectre mitigation: kernel not compiled with retpoline; no mitigation available!");
-       return;
 
-retpoline_auto:
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
-           boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
-       retpoline_amd:
-               if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
-                       pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n");
-                       goto retpoline_generic;
-               }
-               mode = SPECTRE_V2_RETPOLINE_AMD;
-               setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD);
-               setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
-       } else {
-       retpoline_generic:
-               mode = SPECTRE_V2_RETPOLINE_GENERIC;
+       if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+               pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
+
+       if (spectre_v2_in_ibrs_mode(mode)) {
+               x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
+       }
+
+       switch (mode) {
+       case SPECTRE_V2_NONE:
+       case SPECTRE_V2_EIBRS:
+               break;
+
+       case SPECTRE_V2_IBRS:
+               setup_force_cpu_cap(X86_FEATURE_KERNEL_IBRS);
+               break;
+
+       case SPECTRE_V2_LFENCE:
+       case SPECTRE_V2_EIBRS_LFENCE:
+               setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
+               fallthrough;
+
+       case SPECTRE_V2_RETPOLINE:
+       case SPECTRE_V2_EIBRS_RETPOLINE:
                setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
+               break;
        }
 
-specv2_set_mode:
        spectre_v2_enabled = mode;
        pr_info("%s\n", spectre_v2_strings[mode]);
 
        /*
-        * If spectre v2 protection has been enabled, unconditionally fill
-        * RSB during a context switch; this protects against two independent
-        * issues:
+        * If Spectre v2 protection has been enabled, fill the RSB during a
+        * context switch.  In general there are two types of RSB attacks
+        * across context switches, for which the CALLs/RETs may be unbalanced.
+        *
+        * 1) RSB underflow
+        *
+        *    Some Intel parts have "bottomless RSB".  When the RSB is empty,
+        *    speculated return targets may come from the branch predictor,
+        *    which could have a user-poisoned BTB or BHB entry.
+        *
+        *    AMD has it even worse: *all* returns are speculated from the BTB,
+        *    regardless of the state of the RSB.
+        *
+        *    When IBRS or eIBRS is enabled, the "user -> kernel" attack
+        *    scenario is mitigated by the IBRS branch prediction isolation
+        *    properties, so the RSB buffer filling wouldn't be necessary to
+        *    protect against this type of attack.
+        *
+        *    The "user -> user" attack scenario is mitigated by RSB filling.
+        *
+        * 2) Poisoned RSB entry
+        *
+        *    If the 'next' in-kernel return stack is shorter than 'prev',
+        *    'next' could be tricked into speculating with a user-poisoned RSB
+        *    entry.
+        *
+        *    The "user -> kernel" attack scenario is mitigated by SMEP and
+        *    eIBRS.
+        *
+        *    The "user -> user" scenario, also known as SpectreBHB, requires
+        *    RSB clearing.
         *
-        *      - RSB underflow (and switch to BTB) on Skylake+
-        *      - SpectreRSB variant of spectre v2 on X86_BUG_SPECTRE_V2 CPUs
+        * So to mitigate all cases, unconditionally fill RSB on context
+        * switches.
+        *
+        * FIXME: Is this pointless for retbleed-affected AMD?
         */
        setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
        pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
 
        /*
-        * Retpoline means the kernel is safe because it has no indirect
-        * branches. Enhanced IBRS protects firmware too, so, enable restricted
-        * speculation around firmware calls only when Enhanced IBRS isn't
-        * supported.
+        * Similar to context switches, there are two types of RSB attacks
+        * after vmexit:
+        *
+        * 1) RSB underflow
+        *
+        * 2) Poisoned RSB entry
+        *
+        * When retpoline is enabled, both are mitigated by filling/clearing
+        * the RSB.
+        *
+        * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
+        * prediction isolation protections, RSB still needs to be cleared
+        * because of #2.  Note that SMEP provides no protection here, unlike
+        * user-space-poisoned RSB entries.
+        *
+        * eIBRS, on the other hand, has RSB-poisoning protections, so it
+        * doesn't need RSB clearing after vmexit.
+        */
+       if (boot_cpu_has(X86_FEATURE_RETPOLINE) ||
+           boot_cpu_has(X86_FEATURE_KERNEL_IBRS))
+               setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+
+       /*
+        * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
+        * and Enhanced IBRS protect firmware too, so enable IBRS around
+        * firmware calls only when IBRS / Enhanced IBRS aren't otherwise
+        * enabled.
         *
         * Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
         * the user might select retpoline on the kernel command line and if
         * the CPU supports Enhanced IBRS, kernel might un-intentionally not
         * enable IBRS around firmware calls.
         */
-       if (boot_cpu_has(X86_FEATURE_IBRS) && mode != SPECTRE_V2_IBRS_ENHANCED) {
+       if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_ibrs_mode(mode)) {
                setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
                pr_info("Enabling Restricted Speculation for firmware calls\n");
        }
 
        /* Set up IBPB and STIBP depending on the general spectre V2 command */
-       spectre_v2_user_select_mitigation(cmd);
+       spectre_v2_cmd = cmd;
 }
 
 static void update_stibp_msr(void * __unused)
 {
-       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+       u64 val = spec_ctrl_current() | (x86_spec_ctrl_base & SPEC_CTRL_STIBP);
+       write_spec_ctrl_current(val, true);
 }
 
 /* Update x86_spec_ctrl_base in case SMT state changed. */
@@ -1028,6 +1515,8 @@ static void update_indir_branch_cond(void)
 /* Update the static key controlling the MDS CPU buffer clear in idle */
 static void update_mds_branch_idle(void)
 {
+       u64 ia32_cap = x86_read_arch_cap_msr();
+
        /*
         * Enable the idle clearing if SMT is active on CPUs which are
         * affected only by MSBDS and not any other MDS variant.
@@ -1039,19 +1528,26 @@ static void update_mds_branch_idle(void)
        if (!boot_cpu_has_bug(X86_BUG_MSBDS_ONLY))
                return;
 
-       if (sched_smt_active())
+       if (sched_smt_active()) {
                static_branch_enable(&mds_idle_clear);
-       else
+       } else if (mmio_mitigation == MMIO_MITIGATION_OFF ||
+                  (ia32_cap & ARCH_CAP_FBSDP_NO)) {
                static_branch_disable(&mds_idle_clear);
+       }
 }
 
 #define MDS_MSG_SMT "MDS CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html for more details.\n"
 #define TAA_MSG_SMT "TAA CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/tsx_async_abort.html for more details.\n"
+#define MMIO_MSG_SMT "MMIO Stale Data CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/processor_mmio_stale_data.html for more details.\n"
 
 void cpu_bugs_smt_update(void)
 {
        mutex_lock(&spec_ctrl_mutex);
 
+       if (sched_smt_active() && unprivileged_ebpf_enabled() &&
+           spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE)
+               pr_warn_once(SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG);
+
        switch (spectre_v2_user_stibp) {
        case SPECTRE_V2_USER_NONE:
                break;
@@ -1087,6 +1583,16 @@ void cpu_bugs_smt_update(void)
                break;
        }
 
+       switch (mmio_mitigation) {
+       case MMIO_MITIGATION_VERW:
+       case MMIO_MITIGATION_UCODE_NEEDED:
+               if (sched_smt_active())
+                       pr_warn_once(MMIO_MSG_SMT);
+               break;
+       case MMIO_MITIGATION_OFF:
+               break;
+       }
+
        mutex_unlock(&spec_ctrl_mutex);
 }
 
@@ -1190,16 +1696,6 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
                break;
        }
 
-       /*
-        * If SSBD is controlled by the SPEC_CTRL MSR, then set the proper
-        * bit in the mask to allow guests to use the mitigation even in the
-        * case where the host does not enable it.
-        */
-       if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-           static_cpu_has(X86_FEATURE_AMD_SSBD)) {
-               x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
-       }
-
        /*
         * We have three CPU feature flags that are in play here:
         *  - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible.
@@ -1217,7 +1713,7 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
                        x86_amd_ssb_disable();
                } else {
                        x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
-                       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+                       write_spec_ctrl_current(x86_spec_ctrl_base, true);
                }
        }
 
@@ -1468,7 +1964,7 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
 void x86_spec_ctrl_setup_ap(void)
 {
        if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
-               wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
 
        if (ssb_mode == SPEC_STORE_BYPASS_DISABLE)
                x86_amd_ssb_disable();
@@ -1689,9 +2185,23 @@ static ssize_t tsx_async_abort_show_state(char *buf)
                       sched_smt_active() ? "vulnerable" : "disabled");
 }
 
+static ssize_t mmio_stale_data_show_state(char *buf)
+{
+       if (mmio_mitigation == MMIO_MITIGATION_OFF)
+               return sysfs_emit(buf, "%s\n", mmio_strings[mmio_mitigation]);
+
+       if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
+               return sysfs_emit(buf, "%s; SMT Host state unknown\n",
+                                 mmio_strings[mmio_mitigation]);
+       }
+
+       return sysfs_emit(buf, "%s; SMT %s\n", mmio_strings[mmio_mitigation],
+                         sched_smt_active() ? "vulnerable" : "disabled");
+}
+
 static char *stibp_state(void)
 {
-       if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
+       if (spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return "";
 
        switch (spectre_v2_user_stibp) {
@@ -1721,11 +2231,50 @@ static char *ibpb_state(void)
        return "";
 }
 
+static ssize_t spectre_v2_show_state(char *buf)
+{
+       if (spectre_v2_enabled == SPECTRE_V2_LFENCE)
+               return sprintf(buf, "Vulnerable: LFENCE\n");
+
+       if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+               return sprintf(buf, "Vulnerable: eIBRS with unprivileged eBPF\n");
+
+       if (sched_smt_active() && unprivileged_ebpf_enabled() &&
+           spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE)
+               return sprintf(buf, "Vulnerable: eIBRS+LFENCE with unprivileged eBPF and SMT\n");
+
+       return sprintf(buf, "%s%s%s%s%s%s\n",
+                      spectre_v2_strings[spectre_v2_enabled],
+                      ibpb_state(),
+                      boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "",
+                      stibp_state(),
+                      boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "",
+                      spectre_v2_module_string());
+}
+
 static ssize_t srbds_show_state(char *buf)
 {
        return sprintf(buf, "%s\n", srbds_strings[srbds_mitigation]);
 }
 
+static ssize_t retbleed_show_state(char *buf)
+{
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+           if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+               boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                   return sprintf(buf, "Vulnerable: untrained return thunk on non-Zen uarch\n");
+
+           return sprintf(buf, "%s; SMT %s\n",
+                          retbleed_strings[retbleed_mitigation],
+                          !sched_smt_active() ? "disabled" :
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ?
+                          "enabled with STIBP protection" : "vulnerable");
+       }
+
+       return sprintf(buf, "%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
 static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr,
                               char *buf, unsigned int bug)
 {
@@ -1746,12 +2295,7 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
                return sprintf(buf, "%s\n", spectre_v1_strings[spectre_v1_mitigation]);
 
        case X86_BUG_SPECTRE_V2:
-               return sprintf(buf, "%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
-                              ibpb_state(),
-                              boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "",
-                              stibp_state(),
-                              boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "",
-                              spectre_v2_module_string());
+               return spectre_v2_show_state(buf);
 
        case X86_BUG_SPEC_STORE_BYPASS:
                return sprintf(buf, "%s\n", ssb_strings[ssb_mode]);
@@ -1773,6 +2317,12 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
        case X86_BUG_SRBDS:
                return srbds_show_state(buf);
 
+       case X86_BUG_MMIO_STALE_DATA:
+               return mmio_stale_data_show_state(buf);
+
+       case X86_BUG_RETBLEED:
+               return retbleed_show_state(buf);
+
        default:
                break;
        }
@@ -1824,4 +2374,14 @@ ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr, char *
 {
        return cpu_show_common(dev, attr, buf, X86_BUG_SRBDS);
 }
+
+ssize_t cpu_show_mmio_stale_data(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
+}
+
+ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_RETBLEED);
+}
 #endif