Hello, On Tue, 24 Apr 2018 14:15:55 +1000 Michael Ellerman <m...@ellerman.id.au> wrote:
> From: Michal Suchanek <msucha...@suse.de> > > Based on the RFI patching. This is required to be able to disable the > speculation barrier. why do you not patch the nospec barrier which is included as part of the RFI flush code? I think when debugging the code it would make more sense if RFI is patched by RFI patcher and nospec by nospec patcher. A separate question is if the RFI flush would break without the nospec barrier. Thanks Michal > > Only one barrier type is supported and it does nothing when the > firmware does not enable it. Also re-patching modules is not supported > So the only meaningful thing that can be done is patching out the > speculation barrier at boot when the user says it is not wanted. > > Signed-off-by: Michal Suchanek <msucha...@suse.de> > Signed-off-by: Michael Ellerman <m...@ellerman.id.au> > --- > arch/powerpc/include/asm/barrier.h | 2 +- > arch/powerpc/include/asm/feature-fixups.h | 9 +++++++++ > arch/powerpc/include/asm/setup.h | 1 + > arch/powerpc/kernel/security.c | 9 +++++++++ > arch/powerpc/kernel/vmlinux.lds.S | 7 +++++++ > arch/powerpc/lib/feature-fixups.c | 27 > +++++++++++++++++++++++++++ 6 files changed, 54 insertions(+), 1 > deletion(-) > > diff --git a/arch/powerpc/include/asm/barrier.h > b/arch/powerpc/include/asm/barrier.h index e582d2c88092..f67b3f6e36be > 100644 --- a/arch/powerpc/include/asm/barrier.h > +++ b/arch/powerpc/include/asm/barrier.h > @@ -81,7 +81,7 @@ do > { > \ > * Prevent execution of subsequent instructions until preceding > branches have > * been fully resolved and are no longer executing speculatively. > */ > -#define barrier_nospec_asm ori 31,31,0 > +#define barrier_nospec_asm NOSPEC_BARRIER_FIXUP_SECTION; nop > > // This also acts as a compiler barrier due to the memory clobber. > #define barrier_nospec() asm (stringify_in_c(barrier_nospec_asm) ::: > "memory") diff --git a/arch/powerpc/include/asm/feature-fixups.h > b/arch/powerpc/include/asm/feature-fixups.h index > 1e82eb3caabd..86ac59e75f36 100644 --- > a/arch/powerpc/include/asm/feature-fixups.h +++ > b/arch/powerpc/include/asm/feature-fixups.h @@ -195,11 +195,20 @@ > label##3: \ > FTR_ENTRY_OFFSET 951b-952b; \ .popsection; > > +#define NOSPEC_BARRIER_FIXUP_SECTION \ > +953: \ > + .pushsection __barrier_nospec_fixup,"a"; \ > + .align 2; \ > +954: \ > + FTR_ENTRY_OFFSET 953b-954b; \ > + .popsection; > + > > #ifndef __ASSEMBLY__ > #include <linux/types.h> > > extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; > +extern long __start___barrier_nospec_fixup, > __stop___barrier_nospec_fixup; > void apply_feature_fixups(void); > void setup_feature_keys(void); > diff --git a/arch/powerpc/include/asm/setup.h > b/arch/powerpc/include/asm/setup.h index 27fa52ed6d00..afc7280cce3b > 100644 --- a/arch/powerpc/include/asm/setup.h > +++ b/arch/powerpc/include/asm/setup.h > @@ -52,6 +52,7 @@ enum l1d_flush_type { > > void setup_rfi_flush(enum l1d_flush_type, bool enable); > void do_rfi_flush_fixups(enum l1d_flush_type types); > +void do_barrier_nospec_fixups(bool enable); > > #endif /* !__ASSEMBLY__ */ > > diff --git a/arch/powerpc/kernel/security.c > b/arch/powerpc/kernel/security.c index bab5a27ea805..b963eae0b0a0 > 100644 --- a/arch/powerpc/kernel/security.c > +++ b/arch/powerpc/kernel/security.c > @@ -9,10 +9,19 @@ > #include <linux/seq_buf.h> > > #include <asm/security_features.h> > +#include <asm/setup.h> > > > unsigned long powerpc_security_features __read_mostly = > SEC_FTR_DEFAULT; > +static bool barrier_nospec_enabled; > + > +static void enable_barrier_nospec(bool enable) > +{ > + barrier_nospec_enabled = enable; > + do_barrier_nospec_fixups(enable); > +} > + > ssize_t cpu_show_meltdown(struct device *dev, struct > device_attribute *attr, char *buf) { > bool thread_priv; > diff --git a/arch/powerpc/kernel/vmlinux.lds.S > b/arch/powerpc/kernel/vmlinux.lds.S index c8af90ff49f0..ff73f498568c > 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S > +++ b/arch/powerpc/kernel/vmlinux.lds.S > @@ -139,6 +139,13 @@ SECTIONS > *(__rfi_flush_fixup) > __stop___rfi_flush_fixup = .; > } > + > + . = ALIGN(8); > + __spec_barrier_fixup : AT(ADDR(__spec_barrier_fixup) - > LOAD_OFFSET) { > + __start___barrier_nospec_fixup = .; > + *(__barrier_nospec_fixup) > + __stop___barrier_nospec_fixup = .; > + } > #endif > > EXCEPTION_TABLE(0) > diff --git a/arch/powerpc/lib/feature-fixups.c > b/arch/powerpc/lib/feature-fixups.c index 288fe4f0db4e..093c1d2ea5fd > 100644 --- a/arch/powerpc/lib/feature-fixups.c > +++ b/arch/powerpc/lib/feature-fixups.c > @@ -162,6 +162,33 @@ void do_rfi_flush_fixups(enum l1d_flush_type > types) (types & L1D_FLUSH_MTTRIG) ? "mttrig type" > : "unknown"); > } > + > +void do_barrier_nospec_fixups(bool enable) > +{ > + unsigned int instr, *dest; > + long *start, *end; > + int i; > + > + start = PTRRELOC(&__start___barrier_nospec_fixup), > + end = PTRRELOC(&__stop___barrier_nospec_fixup); > + > + instr = 0x60000000; /* nop */ > + > + if (enable) { > + pr_info("barrier-nospec: using ORI speculation > barrier\n"); > + instr = 0x63ff0000; /* ori 31,31,0 speculation > barrier */ > + } > + > + for (i = 0; start < end; start++, i++) { > + dest = (void *)start + *start; > + > + pr_devel("patching dest %lx\n", (unsigned long)dest); > + patch_instruction(dest, instr); > + } > + > + printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", > i); +} > + > #endif /* CONFIG_PPC_BOOK3S_64 */ > > void do_lwsync_fixups(unsigned long value, void *fixup_start, void > *fixup_end)