summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Muellner <christoph.muellner@theobroma-systems.com>2018-05-15 15:26:10 +0200
committerChristoph Muellner <christoph.muellner@theobroma-systems.com>2018-05-23 13:00:54 +0200
commita7c5501f677041edd955a7f76f2cd695f2238f8e (patch)
treed3ad6bb64d74994e3effc29370ff1a5999ad35fd
parent4891e78649d273115d2943721d8974c72e0a15df (diff)
arm64: Use alternative framework for retpoline.
This reduces the impact of retpoline on non-affected processors. By default the retpoline will consist of 6 nop instructions. In case an affected processor is detected (by a MIDR match) the nops will be replaced by the retpoline. The processors, which are using this are Applied Micro's X-Gene1, X-Gene2, X-Gene3, and Ampere Computing's eMAG1. Signed-off-by: Christoph Muellner <christoph.muellner@theobroma-systems.com>
-rw-r--r--arch/arm64/include/asm/cpucaps.h3
-rw-r--r--arch/arm64/include/asm/nospec-branch.h5
-rw-r--r--arch/arm64/kernel/cpu_errata.c58
3 files changed, 65 insertions, 1 deletions
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index bb263820de13..1a4513277802 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -45,7 +45,8 @@
#define ARM64_HARDEN_BRANCH_PREDICTOR 24
#define ARM64_HARDEN_BP_POST_GUEST_EXIT 25
#define ARM64_HAS_RAS_EXTN 26
+#define ARM64_RETPOLINE 27
-#define ARM64_NCAPS 27
+#define ARM64_NCAPS 28
#endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/nospec-branch.h b/arch/arm64/include/asm/nospec-branch.h
index 463ec183f4ec..63db0e2b19a2 100644
--- a/arch/arm64/include/asm/nospec-branch.h
+++ b/arch/arm64/include/asm/nospec-branch.h
@@ -3,9 +3,13 @@
#ifndef _ASM_ARM64_NOSPEC_BRANCH_H_
#define _ASM_ARM64_NOSPEC_BRANCH_H_
+#include <asm/alternative.h>
+#include <asm/cpucaps.h>
+
#ifdef __ASSEMBLY__
.macro retpoline
+alternative_if ARM64_RETPOLINE
str x30, [sp, #-16]!
bl 101f
100: //speculation trap
@@ -16,6 +20,7 @@
ret
102: //non-spec code
ldr x30, [sp], #16
+alternative_else_nop_endif
.endm
.macro br_nospec reg
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index b5a28336c077..d9bc01ef8ed3 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -242,6 +242,54 @@ static int qcom_enable_link_stack_sanitization(void *data)
.midr_range_min = 0, \
.midr_range_max = (MIDR_VARIANT_MASK | MIDR_REVISION_MASK)
+#ifdef CONFIG_RETPOLINE
+
+static inline bool retp_compiler(void)
+{
+ return __is_defined(RETPOLINE);
+}
+
+/* The Spectre V2 mitigation variants */
+enum spectre_v2_mitigation {
+ SPECTRE_V2_NOT_AFFECTED,
+ SPECTRE_V2_RETPOLINE_MINIMAL,
+ SPECTRE_V2_RETPOLINE_GENERIC,
+};
+
+static const char *spectre_v2_strings[] = {
+ [SPECTRE_V2_NOT_AFFECTED] = "Not affected",
+ [SPECTRE_V2_RETPOLINE_MINIMAL] = "Vulnerable: Minimal ASM retpoline",
+ [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full retpoline",
+};
+
+static enum spectre_v2_mitigation spectre_v2_enabled = SPECTRE_V2_NOT_AFFECTED;
+
+static bool spectre_v2_bad_module;
+
+bool retpoline_module_ok(bool has_retpoline)
+{
+ if (has_retpoline)
+ return true;
+
+ pr_err("System may be vulnerable to spectre v2\n");
+ spectre_v2_bad_module = true;
+ return false;
+}
+
+static inline const char *spectre_v2_module_string(void)
+{
+ return spectre_v2_bad_module ? " - vulnerable module loaded" : "";
+}
+
+static void
+enable_retpoline(const struct arm64_cpu_capabilities *entry)
+{
+ spectre_v2_enabled = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC :
+ SPECTRE_V2_RETPOLINE_MINIMAL;
+}
+
+#endif
+
const struct arm64_cpu_capabilities arm64_errata[] = {
#if defined(CONFIG_ARM64_ERRATUM_826319) || \
defined(CONFIG_ARM64_ERRATUM_827319) || \
@@ -426,6 +474,16 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
.enable = enable_smccc_arch_workaround_1,
},
#endif
+#ifdef CONFIG_RETPOLINE
+ {
+ .desc = "speculative branch prediction using retpoline",
+ .capability = ARM64_RETPOLINE,
+ .type = ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE,
+ .cpu_enable = enable_retpoline,
+ .matches = is_affected_midr_range,
+ .midr_range = MIDR_RANGE(MIDR_APM_POTENZA, 0, 0, 3, 1),
+ },
+#endif
{
}
};