Add the minimal infrastructure to control the speculation control feature.

 - Integrate it into the spectre_v2 coammand line parser and the mitigation
   selector function. The conditional selector function is a placeholder
   right now, which needs to be expanded with CPU specific decision
   functions.

 - Provide a static key for the actual code control.  

 - Provide a init function which is called after jump label patching is
   functional.

 - Provide an interface for the late micro code loader to allow late
   discovery of the IBRS support. Not yet functional.

Signed-off-by: Thomas Gleixner <t...@linutronix.de>
---
 arch/x86/include/asm/nospec-branch.h |    9 +++++
 arch/x86/kernel/cpu/Makefile         |    1 
 arch/x86/kernel/cpu/bugs.c           |   17 +++++++++
 arch/x86/kernel/cpu/specctrl.c       |   62 +++++++++++++++++++++++++++++++++++
 4 files changed, 89 insertions(+)

--- a/arch/x86/include/asm/nospec-branch.h
+++ b/arch/x86/include/asm/nospec-branch.h
@@ -3,6 +3,8 @@
 #ifndef __NOSPEC_BRANCH_H__
 #define __NOSPEC_BRANCH_H__
 
+#include <linux/static_key.h>
+
 #include <asm/alternative.h>
 #include <asm/alternative-asm.h>
 #include <asm/cpufeatures.h>
@@ -165,5 +167,12 @@ enum spectre_v2_mitigation {
 enum spectre_v2_mitigation spectre_v2_enabled;
 void spectre_v2_select_mitigation(void);
 
+DECLARE_STATIC_KEY_FALSE(specctrl_ibrs);
+
+void specctrl_init_features(void);
+void specctrl_update_features(void);
+bool specctrl_force_enable_ibrs(void);
+bool specctrl_cond_enable_ibrs(bool full_retpoline);
+
 #endif /* __ASSEMBLY__ */
 #endif /* __NOSPEC_BRANCH_H__ */
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -24,6 +24,7 @@ obj-y                 += match.o
 obj-y                  += bugs.o
 obj-$(CONFIG_CPU_FREQ) += aperfmperf.o
 obj-y                  += cpuid-deps.o
+obj-y                  += specctrl.c
 
 obj-$(CONFIG_PROC_FS)  += proc.o
 obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -79,6 +79,7 @@ enum spectre_v2_mitigation_cmd {
        SPECTRE_V2_CMD_RETPOLINE,
        SPECTRE_V2_CMD_RETPOLINE_GENERIC,
        SPECTRE_V2_CMD_RETPOLINE_AMD,
+       SPECTRE_V2_CMD_IBRS,
 };
 
 static const char *spectre_v2_strings[] = {
@@ -87,6 +88,7 @@ static const char *spectre_v2_strings[]
        [SPECTRE_V2_RETPOLINE_MINIMAL_AMD]      = "Mitigation: Minimal AMD ASM 
retpoline",
        [SPECTRE_V2_RETPOLINE_GENERIC]          = "Mitigation: Full generic 
retpoline",
        [SPECTRE_V2_RETPOLINE_AMD]              = "Mitigation: Full AMD 
retpoline",
+       [SPECTRE_V2_IBRS]                       = "Mitigation: Indirect Branch 
Restricted Speculation",
 };
 
 #undef pr_fmt
@@ -163,6 +165,7 @@ static void __init spectre_v2_check_boot
 
 void spectre_v2_select_mitigation(void)
 {
+       bool full_retpoline = IS_ENABLED(CONFIG_RETPOLINE) && retp_compiler();
        enum spectre_v2_mitigation mode = SPECTRE_V2_NONE;
 
        /*
@@ -178,9 +181,22 @@ void spectre_v2_select_mitigation(void)
        case SPECTRE_V2_CMD_NONE:
                return;
 
+       case SPECTRE_V2_CMD_IBRS:
+               /* Command line requested IBRS. Try to enable it */
+               if (specctrl_force_enable_ibrs()) {
+                       mode = SPECTRE_V2_IBRS;
+                       goto set_mode;
+               }
+               /* FALLTRHU */
+
        case SPECTRE_V2_CMD_FORCE:
                /* FALLTRHU */
        case SPECTRE_V2_CMD_AUTO:
+               /* Check whether the CPU prefers to have IBRS */
+               if (specctrl_cond_enable_ibrs(full_retpoline)) {
+                       mode = SPECTRE_V2_IBRS;
+                       goto set_mode;
+               }
                goto retpoline_auto;
 
        case SPECTRE_V2_CMD_RETPOLINE_AMD:
@@ -223,6 +239,7 @@ void spectre_v2_select_mitigation(void)
                setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
        }
 
+set_mode:
        if (spectre_v2_enabled == mode)
                return;
        spectre_v2_enabled = mode;
--- /dev/null
+++ b/arch/x86/kernel/cpu/specctrl.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <asm/nospec-branch.h>
+#include <asm/cpufeatures.h>
+
+/* Static key to control enablement of IBRS */
+DEFINE_STATIC_KEY_FALSE(specctrl_ibrs);
+
+/**
+ * specctrl_init_features - Init speculation control features
+ *
+ * Called after static key patching is functional. The decision which
+ * mitigation to use has been made already in check_bugs() before patching
+ * the alternatives.
+ */
+void __init specctrl_init_features(void)
+{
+       if (spectre_v2_enabled != SPECTRE_V2_IBRS)
+               return;
+
+       static_branch_enable(&specctrl_ibrs);
+}
+
+/**
+ * specctrl_update_features - Update the speculation control features
+ *
+ * Called after a late microcode load changed CPU feature bits.
+ *
+ * Note: This is called with CPU hotplug lock and microcode mutex held.
+ */
+void specctrl_update_features(void)
+{
+       if (static_key_enabled(&specctrl_ibrs))
+               return;
+
+       /*
+        * FIXME: Either the CPU bits need to be reevaluated here or its
+        * done in the late microcode loader. Borislav ?
+        */
+       spectre_v2_select_mitigation();
+       if (spectre_v2_enabled != SPECTRE_V2_IBRS)
+               return;
+       static_branch_enable_cpuslocked(&specctrl_ibrs);
+}
+
+bool specctrl_force_enable_ibrs(void)
+{
+       if (!boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+               return false;
+       return true;
+}
+
+bool specctrl_cond_enable_ibrs(bool full_retpoline)
+{
+       if (!boot_cpu_has(X86_FEATURE_SPEC_CTRL))
+               return false;
+       /*
+        * FIXME: Add logic here to decide what the best option is for a
+        * particular CPU.
+        */
+       return true;
+}


Reply via email to