]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
arm64: Use the clearbhb instruction in mitigations
authorJames Morse <james.morse@arm.com>
Thu, 31 Mar 2022 18:34:00 +0000 (19:34 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 2 Apr 2022 10:41:10 +0000 (12:41 +0200)
commit 228a26b912287934789023b4132ba76065d9491c upstream.

Future CPUs may implement a clearbhb instruction that is sufficient
to mitigate SpectreBHB. CPUs that implement this instruction, but
not CSV2.3 must be affected by Spectre-BHB.

Add support to use this instruction as the BHB mitigation on CPUs
that support it. The instruction is in the hint space, so it will
be treated by a NOP as older CPUs.

Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
[ modified for stable: Use a KVM vector template instead of alternatives ]
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/vectors.h
arch/arm64/kernel/bpi.S
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/entry.S

index b84e367e2720c3bfecca080846db2998f5b45268..6b38f3b3095a37b970832f965bcd640dc1e8ab52 100644 (file)
        hint    #20
        .endm
 
+/*
+ * Clear Branch History instruction
+ */
+       .macro clearbhb
+       hint    #22
+       .endm
+
 /*
  * Sanitise a 64-bit bounded index wrt speculation, returning zero if out
  * of bounds.
index 4c23c57780306fc2a04e05bb7fd4d130c2b789ca..3e9d042d1b1e777052229e39ed362d8108aff74f 100644 (file)
@@ -471,6 +471,19 @@ static inline bool supports_csv2p3(int scope)
        return csv2_val == 3;
 }
 
+static inline bool supports_clearbhb(int scope)
+{
+       u64 isar2;
+
+       if (scope == SCOPE_LOCAL_CPU)
+               isar2 = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
+       else
+               isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
+
+       return cpuid_feature_extract_unsigned_field(isar2,
+                                                   ID_AA64ISAR2_CLEARBHB_SHIFT);
+}
+
 static inline bool system_supports_32bit_el0(void)
 {
        return cpus_have_const_cap(ARM64_HAS_32BIT_EL0);
index 2ea15f07835470a39ea1c611cc984d653022c69a..3bbf0dc5ecad0235c4f8565627d9ccba75b61f76 100644 (file)
 #define ID_AA64ISAR1_JSCVT_SHIFT       12
 #define ID_AA64ISAR1_DPB_SHIFT         0
 
+/* id_aa64isar2 */
+#define ID_AA64ISAR2_CLEARBHB_SHIFT    28
+
 /* id_aa64pfr0 */
 #define ID_AA64PFR0_CSV3_SHIFT         60
 #define ID_AA64PFR0_CSV2_SHIFT         56
index f222d8e033b32c821cb99228f18240ab3e5f9307..695583b9a145b79b539295db8cea221da8ea47a4 100644 (file)
@@ -33,6 +33,12 @@ enum arm64_bp_harden_el1_vectors {
         * canonical vectors.
         */
        EL1_VECTOR_BHB_FW,
+
+       /*
+        * Use the ClearBHB instruction, before branching to the canonical
+        * vectors.
+        */
+       EL1_VECTOR_BHB_CLEAR_INSN,
 #endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
 
        /*
@@ -44,6 +50,7 @@ enum arm64_bp_harden_el1_vectors {
 #ifndef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
 #define EL1_VECTOR_BHB_LOOP            -1
 #define EL1_VECTOR_BHB_FW              -1
+#define EL1_VECTOR_BHB_CLEAR_INSN      -1
 #endif /* !CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
 
 /* The vectors to use on return from EL0. e.g. to remap the kernel */
index 81f15b49429a99f8b42f3251bab6a92becb90e32..bd6ef8750f440b4743fd52b76a298e0d4b6b99ba 100644 (file)
@@ -116,3 +116,8 @@ ENTRY(__spectre_bhb_loop_k32_start)
        ldp     x0, x1, [sp, #(8 * 0)]
        add     sp, sp, #(8 * 2)
 ENTRY(__spectre_bhb_loop_k32_end)
+
+ENTRY(__spectre_bhb_clearbhb_start)
+       hint    #22     /* aka clearbhb */
+       isb
+ENTRY(__spectre_bhb_clearbhb_end)
index b8f87041f792891a7823deb09bf738488dd00c2e..ed627d44746ada1c27621563bf810edf4ddb3dc1 100644 (file)
@@ -94,6 +94,8 @@ extern char __spectre_bhb_loop_k24_start[];
 extern char __spectre_bhb_loop_k24_end[];
 extern char __spectre_bhb_loop_k32_start[];
 extern char __spectre_bhb_loop_k32_end[];
+extern char __spectre_bhb_clearbhb_start[];
+extern char __spectre_bhb_clearbhb_end[];
 
 static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
                                const char *hyp_vecs_end)
@@ -826,6 +828,7 @@ static void update_mitigation_state(enum mitigation_state *oldp,
  * - Mitigated by a branchy loop a CPU specific number of times, and listed
  *   in our "loop mitigated list".
  * - Mitigated in software by the firmware Spectre v2 call.
+ * - Has the ClearBHB instruction to perform the mitigation.
  * - Has the 'Exception Clears Branch History Buffer' (ECBHB) feature, so no
  *   software mitigation in the vectors is needed.
  * - Has CSV2.3, so is unaffected.
@@ -965,6 +968,9 @@ bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry,
        if (supports_csv2p3(scope))
                return false;
 
+       if (supports_clearbhb(scope))
+               return true;
+
        if (spectre_bhb_loop_affected(scope))
                return true;
 
@@ -1005,6 +1011,8 @@ static const char *kvm_bhb_get_vecs_end(const char *start)
                return __spectre_bhb_loop_k24_end;
        else if (start == __spectre_bhb_loop_k32_start)
                return __spectre_bhb_loop_k32_end;
+       else if (start == __spectre_bhb_clearbhb_start)
+               return __spectre_bhb_clearbhb_end;
 
        return NULL;
 }
@@ -1046,6 +1054,7 @@ static void kvm_setup_bhb_slot(const char *hyp_vecs_start)
 #define __spectre_bhb_loop_k8_start NULL
 #define __spectre_bhb_loop_k24_start NULL
 #define __spectre_bhb_loop_k32_start NULL
+#define __spectre_bhb_clearbhb_start NULL
 
 static void kvm_setup_bhb_slot(const char *hyp_vecs_start) { };
 #endif
@@ -1064,6 +1073,11 @@ void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry)
        } else if (cpu_mitigations_off()) {
                pr_info_once("spectre-bhb mitigation disabled by command line option\n");
        } else if (supports_ecbhb(SCOPE_LOCAL_CPU)) {
+               state = SPECTRE_MITIGATED;
+       } else if (supports_clearbhb(SCOPE_LOCAL_CPU)) {
+               kvm_setup_bhb_slot(__spectre_bhb_clearbhb_start);
+               this_cpu_set_vectors(EL1_VECTOR_BHB_CLEAR_INSN);
+
                state = SPECTRE_MITIGATED;
        } else if (spectre_bhb_loop_affected(SCOPE_LOCAL_CPU)) {
                switch (spectre_bhb_loop_affected(SCOPE_SYSTEM)) {
index 8c655a9dabfc4058ebe564dc0d1cd05a1b114e66..b6922f33d306b4743c2a6319efb19184c3b2aff8 100644 (file)
@@ -135,6 +135,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_CLEARBHB_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
 
index 54f9d95e4909cd35da193688394cb06ece107a6d..f526148d14bd81f3570ef241e21e572f523c29eb 100644 (file)
@@ -1033,6 +1033,7 @@ alternative_else_nop_endif
 #define BHB_MITIGATION_NONE    0
 #define BHB_MITIGATION_LOOP    1
 #define BHB_MITIGATION_FW      2
+#define BHB_MITIGATION_INSN    3
 
        .macro tramp_ventry, vector_start, regsize, kpti, bhb
        .align  7
@@ -1049,6 +1050,11 @@ alternative_else_nop_endif
        __mitigate_spectre_bhb_loop     x30
        .endif // \bhb == BHB_MITIGATION_LOOP
 
+       .if     \bhb == BHB_MITIGATION_INSN
+       clearbhb
+       isb
+       .endif // \bhb == BHB_MITIGATION_INSN
+
        .if     \kpti == 1
        /*
         * Defend against branch aliasing attacks by pushing a dummy
@@ -1125,6 +1131,7 @@ ENTRY(tramp_vectors)
 #ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
        generate_tramp_vector   kpti=1, bhb=BHB_MITIGATION_LOOP
        generate_tramp_vector   kpti=1, bhb=BHB_MITIGATION_FW
+       generate_tramp_vector   kpti=1, bhb=BHB_MITIGATION_INSN
 #endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
        generate_tramp_vector   kpti=1, bhb=BHB_MITIGATION_NONE
 END(tramp_vectors)
@@ -1187,6 +1194,7 @@ ENTRY(__bp_harden_el1_vectors)
 #ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
        generate_el1_vector     bhb=BHB_MITIGATION_LOOP
        generate_el1_vector     bhb=BHB_MITIGATION_FW
+       generate_el1_vector     bhb=BHB_MITIGATION_INSN
 #endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
 END(__bp_harden_el1_vectors)
        .popsection