powerpc/fsl: Add infrastructure to fixup branch predictor flush
authorDiana Craciun <diana.craciun@nxp.com>
Wed, 12 Dec 2018 14:03:00 +0000 (16:03 +0200)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 20 Dec 2018 11:53:39 +0000 (22:53 +1100)
In order to protect against speculation attacks (Spectre
variant 2) on NXP PowerPC platforms, the branch predictor
should be flushed when the privillege level is changed.
This patch is adding the infrastructure to fixup at runtime
the code sections that are performing the branch predictor flush
depending on a boot arg parameter which is added later in a
separate patch.

Signed-off-by: Diana Craciun <diana.craciun@nxp.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/feature-fixups.h
arch/powerpc/include/asm/setup.h
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/lib/feature-fixups.c

index 33b6f9c892c819c62fa6bbbd503d8f1e66cafb21..40a6c9261a6bfab2994fa5fa6e93b70f398ee560 100644 (file)
@@ -221,6 +221,17 @@ label##3:                                          \
        FTR_ENTRY_OFFSET 953b-954b;                     \
        .popsection;
 
+#define START_BTB_FLUSH_SECTION                        \
+955:                                                   \
+
+#define END_BTB_FLUSH_SECTION                  \
+956:                                                   \
+       .pushsection __btb_flush_fixup,"a";     \
+       .align 2;                                                       \
+957:                                           \
+       FTR_ENTRY_OFFSET 955b-957b;                     \
+       FTR_ENTRY_OFFSET 956b-957b;                     \
+       .popsection;
 
 #ifndef __ASSEMBLY__
 #include <linux/types.h>
@@ -230,6 +241,7 @@ extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup;
 extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup;
 extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
 extern long __start___barrier_nospec_fixup, __stop___barrier_nospec_fixup;
+extern long __start__btb_flush_fixup, __stop__btb_flush_fixup;
 
 void apply_feature_fixups(void);
 void setup_feature_keys(void);
index 1fffbba8d6a5e64a5fefdb06a6ecab29f4ec66e5..c941c8c6bfb31f1327b596a79259af268b8f61b4 100644 (file)
@@ -67,6 +67,8 @@ void do_barrier_nospec_fixups_range(bool enable, void *start, void *end);
 static inline void do_barrier_nospec_fixups_range(bool enable, void *start, void *end) { };
 #endif
 
+void do_btb_flush_fixups(void);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_SETUP_H */
index e1ce0aedcc9a5e0f9c94b5555da1c423f1206c08..ad1c77f71f5474e91219c36fa827b5079b60be62 100644 (file)
@@ -170,6 +170,14 @@ SECTIONS
        }
 #endif /* CONFIG_PPC_BARRIER_NOSPEC */
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+       . = ALIGN(8);
+       __spec_btb_flush_fixup : AT(ADDR(__spec_btb_flush_fixup) - LOAD_OFFSET) {
+               __start__btb_flush_fixup = .;
+               *(__btb_flush_fixup)
+               __stop__btb_flush_fixup = .;
+       }
+#endif
        EXCEPTION_TABLE(0)
 
        NOTES :kernel :notes
index ca8478503f187a8b7c5dadeedee4eb8d48def416..5169cc805464e432b387f5bf529603df016c1d8c 100644 (file)
@@ -347,6 +347,29 @@ void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_
 
        printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
 }
+
+static void patch_btb_flush_section(long *curr)
+{
+       unsigned int *start, *end;
+
+       start = (void *)curr + *curr;
+       end = (void *)curr + *(curr + 1);
+       for (; start < end; start++) {
+               pr_devel("patching dest %lx\n", (unsigned long)start);
+               patch_instruction(start, PPC_INST_NOP);
+       }
+}
+
+void do_btb_flush_fixups(void)
+{
+       long *start, *end;
+
+       start = PTRRELOC(&__start__btb_flush_fixup);
+       end = PTRRELOC(&__stop__btb_flush_fixup);
+
+       for (; start < end; start += 2)
+               patch_btb_flush_section(start);
+}
 #endif /* CONFIG_PPC_FSL_BOOK3E */
 
 void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)