PR target/86951 arm - Handle speculation barriers on pre-armv7 CPUs
authorRichard Earnshaw <rearnsha@arm.com>
Thu, 23 Aug 2018 09:47:34 +0000 (09:47 +0000)
committerRichard Earnshaw <rearnsha@gcc.gnu.org>
Thu, 23 Aug 2018 09:47:34 +0000 (09:47 +0000)
The AArch32 instruction sets prior to Armv7 do not define the ISB and
DSB instructions that are needed to form a speculation barrier.  While
I do not know of any instances of cores based on those instruction
sets being vulnerable to speculative side channel attacks it is
possible to run code built for those ISAs on more recent hardware
where they would become vulnerable.

This patch works around this by using a library call added to libgcc.
That code can then take any platform-specific actions necessary to
ensure safety.

For the moment I've only handled two cases: the library code being
built for armv7 or later anyway and running on Linux.

On Linux we can handle this by calling the kernel function that will
flush a small amount of cache.  Such a sequence ends with a ISB+DSB
sequence if running on an Armv7 or later CPU.

gcc:

PR target/86951
* config/arm/arm-protos.h (arm_emit_speculation_barrier): New
prototype.
* config/arm/arm.c (speculation_barrier_libfunc): New static
variable.
(arm_init_libfuncs): Initialize it.
(arm_emit_speculation_barrier): New function.
* config/arm/arm.md (speculation_barrier): Call
arm_emit_speculation_barrier for architectures that do not have
DSB or ISB.
(speculation_barrier_insn): Only match on Armv7 or later.

libgcc:

PR target/86951
* config/arm/lib1funcs.asm (speculation_barrier): New function.
* config/arm/t-arm (LIB1ASMFUNCS): Add it to list of functions
to build.

From-SVN: r263806

gcc/ChangeLog
gcc/config/arm/arm-protos.h
gcc/config/arm/arm.c
gcc/config/arm/arm.md
libgcc/ChangeLog
libgcc/config/arm/lib1funcs.S
libgcc/config/arm/t-arm

index 89dfeb9f81fbfd0461d55d260c80be7af8d0ccc5..7b7c79bbb7df6c6636eb60a27351d0e54e12d319 100644 (file)
@@ -1,3 +1,17 @@
+2018-08-23  Richard Earnshaw  <rearnsha@arm.com>
+
+       PR target/86951
+       * config/arm/arm-protos.h (arm_emit_speculation_barrier): New
+       prototype.
+       * config/arm/arm.c (speculation_barrier_libfunc): New static
+       variable.
+       (arm_init_libfuncs): Initialize it.
+       (arm_emit_speculation_barrier): New function.
+       * config/arm/arm.md (speculation_barrier): Call
+       arm_emit_speculation_barrier for architectures that do not have
+       DSB or ISB.
+       (speculation_barrier_insn): Only match on Armv7 or later.
+
 2018-08-23  Richard Biener  <rguenther@suse.de>
 
        PR middle-end/87024
index 8537262ce644bbacd7a800c708bcd86eea93d2bd..0dfb3ac59a6ad33a46256aac5243d8ea46f55131 100644 (file)
@@ -56,6 +56,8 @@ extern void arm_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update
 extern rtx arm_simd_vect_par_cnst_half (machine_mode mode, bool high);
 extern bool arm_simd_check_vect_par_cnst_half_p (rtx op, machine_mode mode,
                                                 bool high);
+extern void arm_emit_speculation_barrier_function (void);
+
 #ifdef RTX_CODE
 extern void arm_gen_unlikely_cbranch (enum rtx_code, machine_mode cc_mode,
                                      rtx label_ref);
index 1d97db50a28b753505f7666548f8b0ccbde02327..c081216decd04e94069940f096b8c70b001f4beb 100644 (file)
@@ -2466,8 +2466,9 @@ arm_set_fixed_conv_libfunc (convert_optab optable, machine_mode to,
   set_conv_libfunc (optable, to, from, buffer);
 }
 
-/* Set up library functions unique to ARM.  */
+static GTY(()) rtx speculation_barrier_libfunc;
 
+/* Set up library functions unique to ARM.  */
 static void
 arm_init_libfuncs (void)
 {
@@ -2753,6 +2754,8 @@ arm_init_libfuncs (void)
 
   if (TARGET_AAPCS_BASED)
     synchronize_libfunc = init_one_libfunc ("__sync_synchronize");
+
+  speculation_barrier_libfunc = init_one_libfunc ("__speculation_barrier");
 }
 
 /* On AAPCS systems, this is the "struct __va_list".  */
@@ -31528,6 +31531,16 @@ arm_constant_alignment (const_tree exp, HOST_WIDE_INT align)
   return align;
 }
 
+/* Emit a speculation barrier on target architectures that do not have
+   DSB/ISB directly.  Such systems probably don't need a barrier
+   themselves, but if the code is ever run on a later architecture, it
+   might become a problem.  */
+void
+arm_emit_speculation_barrier_function ()
+{
+  emit_library_call (speculation_barrier_libfunc, LCT_NORMAL, VOIDmode);
+}
+
 #if CHECKING_P
 namespace selftest {
 
index ca2a2f5469f26d8bca512084c7924708be2715c1..270b8e454b3431b81d20fc26506c2c043933b09b 100644 (file)
   [(unspec_volatile [(const_int 0)] VUNSPEC_SPECULATION_BARRIER)]
   "TARGET_EITHER"
   "
-    /* Don't emit anything for Thumb1 and suppress the warning from the
-       generic expansion.  */
-    if (!TARGET_32BIT)
-       DONE;
+  /* For thumb1 (except Armv8 derivatives), and for pre-Armv7 we don't
+     have a usable barrier (and probably don't need one in practice).
+     But to be safe if such code is run on later architectures, call a
+     helper function in libgcc that will do the thing for the active
+     system.  */
+  if (!(arm_arch7 || arm_arch8))
+    {
+      arm_emit_speculation_barrier_function ();
+      DONE;
+    }
   "
 )
 
 ;; tracking.
 (define_insn "*speculation_barrier_insn"
   [(unspec_volatile [(const_int 0)] VUNSPEC_SPECULATION_BARRIER)]
-  "TARGET_32BIT"
+  "arm_arch7 || arm_arch8"
   "isb\;dsb\\tsy"
   [(set_attr "type" "block")
    (set_attr "length" "8")]
index d003fd54c6e979c20f30644ef1120fdd878bbf67..280bd10286823a3785de64a67959a2098f286b18 100644 (file)
@@ -1,3 +1,10 @@
+2018-08-23  Richard Earnshaw  <rearnsha@arm.com>
+
+       PR target/86951
+       * config/arm/lib1funcs.asm (speculation_barrier): New function.
+       * config/arm/t-arm (LIB1ASMFUNCS): Add it to list of functions
+       to build.
+
 2018-08-22  Iain Sandoe  <iain@sandoe.co.uk>
 
        * config/unwind-dw2-fde-darwin.c 
index b9919aa966de7a771a1745183aba7609dc52e75a..ff06d504a4c940e1fe04cb9b17d5eece131ccc16 100644 (file)
@@ -1533,6 +1533,50 @@ LSYM(Lover12):
 #error "This is only for ARM EABI GNU/Linux"
 #endif
 #endif /* L_clear_cache */
+
+#ifdef L_speculation_barrier
+       FUNC_START speculation_barrier
+#if __ARM_ARCH >= 7
+       isb
+       dsb sy
+#elif defined __ARM_EABI__ && defined __linux__
+       /* We don't have a speculation barrier directly for this
+          platform/architecture variant.  But we can use a kernel
+          clear_cache service routine which will emit such instructions
+          if run on a later version of the architecture.  We don't
+          really want to flush the cache, but we must give it a valid
+          address, so just clear pc..pc+1.  */
+#if defined __thumb__ && !defined __thumb2__
+       push    {r7}
+       mov     r7, #0xf
+       lsl     r7, #16
+       add     r7, #2
+       adr     r0, . + 4
+       add     r1, r0, #1
+       mov     r2, #0
+       svc     0
+       pop     {r7}
+#else
+       do_push {r7}
+#ifdef __ARM_ARCH_6T2__
+       movw    r7, #2
+       movt    r7, #0xf
+#else
+       mov     r7, #0xf0000
+       add     r7, r7, #2
+#endif
+       add     r0, pc, #0      /* ADR.  */
+       add     r1, r0, #1
+       mov     r2, #0
+       svc     0
+       do_pop  {r7}
+#endif /* Thumb1 only */
+#else
+#warning "No speculation barrier defined for this platform"
+#endif
+       RET
+       FUNC_END speculation_barrier
+#endif
 /* ------------------------------------------------------------------------ */
 /* Dword shift operations.  */
 /* All the following Dword shift variants rely on the fact that
index 9e85ac06b146feaa14ab83374a0156737b870310..274bf2a8ef33c5e8a8ee2b246aba92d30297abe1 100644 (file)
@@ -1,6 +1,6 @@
 LIB1ASMSRC = arm/lib1funcs.S
 LIB1ASMFUNCS = _thumb1_case_sqi _thumb1_case_uqi _thumb1_case_shi \
-       _thumb1_case_uhi _thumb1_case_si
+       _thumb1_case_uhi _thumb1_case_si _speculation_barrier
 
 HAVE_CMSE:=$(findstring __ARM_FEATURE_CMSE,$(shell $(gcc_compile_bare) -dM -E - </dev/null))
 ifneq ($(shell $(gcc_compile_bare) -E -mcmse - </dev/null 2>/dev/null),)