Merge tag 'dt-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / arch / x86 / kernel / cpu / bugs.c
index d41b70f..ecfca3b 100644 (file)
@@ -43,6 +43,7 @@ static void __init mds_select_mitigation(void);
 static void __init mds_print_mitigation(void);
 static void __init taa_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. */
 u64 x86_spec_ctrl_base;
@@ -76,6 +77,13 @@ EXPORT_SYMBOL_GPL(mds_user_clear);
 DEFINE_STATIC_KEY_FALSE(mds_idle_clear);
 EXPORT_SYMBOL_GPL(mds_idle_clear);
 
+/*
+ * Controls whether l1d flush based mitigations are enabled,
+ * based on hw features and admin setting via boot parameter
+ * defaults to false
+ */
+DEFINE_STATIC_KEY_FALSE(switch_mm_cond_l1d_flush);
+
 void __init check_bugs(void)
 {
        identify_boot_cpu();
@@ -111,6 +119,7 @@ void __init check_bugs(void)
        mds_select_mitigation();
        taa_select_mitigation();
        srbds_select_mitigation();
+       l1d_flush_select_mitigation();
 
        /*
         * As MDS and TAA mitigations are inter-related, print MDS
@@ -491,6 +500,34 @@ static int __init srbds_parse_cmdline(char *str)
 }
 early_param("srbds", srbds_parse_cmdline);
 
+#undef pr_fmt
+#define pr_fmt(fmt)     "L1D Flush : " fmt
+
+enum l1d_flush_mitigations {
+       L1D_FLUSH_OFF = 0,
+       L1D_FLUSH_ON,
+};
+
+static enum l1d_flush_mitigations l1d_flush_mitigation __initdata = L1D_FLUSH_OFF;
+
+static void __init l1d_flush_select_mitigation(void)
+{
+       if (!l1d_flush_mitigation || !boot_cpu_has(X86_FEATURE_FLUSH_L1D))
+               return;
+
+       static_branch_enable(&switch_mm_cond_l1d_flush);
+       pr_info("Conditional flush on switch_mm() enabled\n");
+}
+
+static int __init l1d_flush_parse_cmdline(char *str)
+{
+       if (!strcmp(str, "on"))
+               l1d_flush_mitigation = L1D_FLUSH_ON;
+
+       return 0;
+}
+early_param("l1d_flush", l1d_flush_parse_cmdline);
+
 #undef pr_fmt
 #define pr_fmt(fmt)     "Spectre V1 : " fmt
 
@@ -1215,6 +1252,24 @@ static void task_update_spec_tif(struct task_struct *tsk)
                speculation_ctrl_update_current();
 }
 
+static int l1d_flush_prctl_set(struct task_struct *task, unsigned long ctrl)
+{
+
+       if (!static_branch_unlikely(&switch_mm_cond_l1d_flush))
+               return -EPERM;
+
+       switch (ctrl) {
+       case PR_SPEC_ENABLE:
+               set_ti_thread_flag(&task->thread_info, TIF_SPEC_L1D_FLUSH);
+               return 0;
+       case PR_SPEC_DISABLE:
+               clear_ti_thread_flag(&task->thread_info, TIF_SPEC_L1D_FLUSH);
+               return 0;
+       default:
+               return -ERANGE;
+       }
+}
+
 static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
 {
        if (ssb_mode != SPEC_STORE_BYPASS_PRCTL &&
@@ -1324,6 +1379,8 @@ int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
                return ssb_prctl_set(task, ctrl);
        case PR_SPEC_INDIRECT_BRANCH:
                return ib_prctl_set(task, ctrl);
+       case PR_SPEC_L1D_FLUSH:
+               return l1d_flush_prctl_set(task, ctrl);
        default:
                return -ENODEV;
        }
@@ -1340,6 +1397,17 @@ void arch_seccomp_spec_mitigate(struct task_struct *task)
 }
 #endif
 
+static int l1d_flush_prctl_get(struct task_struct *task)
+{
+       if (!static_branch_unlikely(&switch_mm_cond_l1d_flush))
+               return PR_SPEC_FORCE_DISABLE;
+
+       if (test_ti_thread_flag(&task->thread_info, TIF_SPEC_L1D_FLUSH))
+               return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
+       else
+               return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
+}
+
 static int ssb_prctl_get(struct task_struct *task)
 {
        switch (ssb_mode) {
@@ -1390,6 +1458,8 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
                return ssb_prctl_get(task);
        case PR_SPEC_INDIRECT_BRANCH:
                return ib_prctl_get(task);
+       case PR_SPEC_L1D_FLUSH:
+               return l1d_flush_prctl_get(task);
        default:
                return -ENODEV;
        }