]> git.ipfire.org Git - people/arne_f/kernel.git/commitdiff
powerpc/fsl: Add infrastructure to fixup branch predictor flush
authorDiana Craciun <diana.craciun@nxp.com>
Thu, 11 Apr 2019 11:46:18 +0000 (21:46 +1000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Apr 2019 06:36:42 +0000 (08:36 +0200)
commit 76a5eaa38b15dda92cd6964248c39b5a6f3a4e9d upstream.

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
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 afd3efd38938496e290598274b74474f6e81b613..175128e19025bafd185aa3933d56d383e592534a 100644 (file)
@@ -221,6 +221,17 @@ void setup_feature_keys(void);
        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__
 
@@ -229,6 +240,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;
 
 #endif
 
index d3e9da62d0292b0bf27932000254a8c33aabdd03..23ee67e279aef38c1e2f788cb1b8aab8ed4d3a1d 100644 (file)
@@ -65,6 +65,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 5c6cf58943b96da278f3ea0d58a087701cdba0ac..50d365060855839a3a76f6b1bd5ff163eb2c904e 100644 (file)
@@ -164,6 +164,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 b3e362437ec40110bb2fa15190806c5fdeda01fa..e6ed0ec94bc8c2fbbae096349148b2b1d09a4018 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)