PR target/86951 arm - Handle speculation barriers on pre-armv7 CPUs

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
This commit is contained in:
Richard Earnshaw 2018-08-23 09:47:34 +00:00 committed by Richard Earnshaw
parent 60d91c7fae
commit ebdb6f2377
7 changed files with 93 additions and 7 deletions

View 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

View 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);

View 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 {

View file

@ -12016,10 +12016,16 @@
[(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;
}
"
)
@ -12027,7 +12033,7 @@
;; 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")]

View 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

View 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

View 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),)