[patch RFC 5/5] x86/speculation: Add basic speculation control code

From: Thomas Gleixner
Date: Tue Jan 09 2018 - 20:22:47 EST


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 <tglx@xxxxxxxxxxxxx>
---
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;
+}