powerpc/64s: Add support for ori barrier_nospec patching
authorMichal Suchanek <msuchanek@suse.de>
Tue, 24 Apr 2018 04:15:55 +0000 (14:15 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Sun, 3 Jun 2018 10:43:44 +0000 (20:43 +1000)
Based on the RFI patching. This is required to be able to disable the
speculation barrier.

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 <msuchanek@suse.de>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/barrier.h
arch/powerpc/include/asm/feature-fixups.h
arch/powerpc/include/asm/setup.h
arch/powerpc/kernel/security.c
arch/powerpc/kernel/vmlinux.lds.S
arch/powerpc/lib/feature-fixups.c

index e582d2c880922504c6d93b3df72f655953437aae..f67b3f6e36bebf85b69f72a913b9800daebbe3c4 100644 (file)
@@ -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")
index 1e82eb3caabd19c69289957da188b563d0bcd0d6..86ac59e75f361963f353b59bd997e3100a85f405 100644 (file)
@@ -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);
index 27fa52ed6d00deac4ed4579c8276c9eb79bc86c3..afc7280cce3b1f91173988d943d29def611c4da2 100644 (file)
@@ -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__ */
 
index bab5a27ea8056c8317340716d33ff084e08d3b2b..b963eae0b0a0ee8223a3994185520bf27caa58a0 100644 (file)
@@ -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;
index c8af90ff49f0526630ffb938c9c5d48cd0279933..ff73f498568cb12c9eae93b3fadb62c4d29e32d5 100644 (file)
@@ -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)
index f3e46d4edd72d48d424c69f9b00de0d9d26eb380..ae911dad9b165e16086326f617cd7e7d725f35d8 100644 (file)
@@ -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)