arm64: lse: fix LSE atomics with LLVM's integrated assembler

[ Upstream commit e0d5896bd3 ]

Unlike gcc, clang considers each inline assembly block to be independent
and therefore, when using the integrated assembler for inline assembly,
any preambles that enable features must be repeated in each block.

This change defines __LSE_PREAMBLE and adds it to each inline assembly
block that has LSE instructions, which allows them to be compiled also
with clang's assembler.

Link: https://github.com/ClangBuiltLinux/linux/issues/671
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Tested-by: Andrew Murray <andrew.murray@arm.com>
Tested-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Andrew Murray <andrew.murray@arm.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Sami Tolvanen 2019-10-31 12:57:05 -07:00 committed by Greg Kroah-Hartman
parent b04235f1e1
commit f686682924
2 changed files with 22 additions and 3 deletions

View File

@ -14,6 +14,7 @@
static inline void __lse_atomic_##op(int i, atomic_t *v) \ static inline void __lse_atomic_##op(int i, atomic_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" " #asm_op " %w[i], %[v]\n" \ " " #asm_op " %w[i], %[v]\n" \
: [i] "+r" (i), [v] "+Q" (v->counter) \ : [i] "+r" (i), [v] "+Q" (v->counter) \
: "r" (v)); \ : "r" (v)); \
@ -30,6 +31,7 @@ ATOMIC_OP(add, stadd)
static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v) \ static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" " #asm_op #mb " %w[i], %w[i], %[v]" \ " " #asm_op #mb " %w[i], %w[i], %[v]" \
: [i] "+r" (i), [v] "+Q" (v->counter) \ : [i] "+r" (i), [v] "+Q" (v->counter) \
: "r" (v) \ : "r" (v) \
@ -58,6 +60,7 @@ static inline int __lse_atomic_add_return##name(int i, atomic_t *v) \
u32 tmp; \ u32 tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" ldadd" #mb " %w[i], %w[tmp], %[v]\n" \ " ldadd" #mb " %w[i], %w[tmp], %[v]\n" \
" add %w[i], %w[i], %w[tmp]" \ " add %w[i], %w[i], %w[tmp]" \
: [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \
@ -77,6 +80,7 @@ ATOMIC_OP_ADD_RETURN( , al, "memory")
static inline void __lse_atomic_and(int i, atomic_t *v) static inline void __lse_atomic_and(int i, atomic_t *v)
{ {
asm volatile( asm volatile(
__LSE_PREAMBLE
" mvn %w[i], %w[i]\n" " mvn %w[i], %w[i]\n"
" stclr %w[i], %[v]" " stclr %w[i], %[v]"
: [i] "+&r" (i), [v] "+Q" (v->counter) : [i] "+&r" (i), [v] "+Q" (v->counter)
@ -87,6 +91,7 @@ static inline void __lse_atomic_and(int i, atomic_t *v)
static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v) \ static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" mvn %w[i], %w[i]\n" \ " mvn %w[i], %w[i]\n" \
" ldclr" #mb " %w[i], %w[i], %[v]" \ " ldclr" #mb " %w[i], %w[i], %[v]" \
: [i] "+&r" (i), [v] "+Q" (v->counter) \ : [i] "+&r" (i), [v] "+Q" (v->counter) \
@ -106,6 +111,7 @@ ATOMIC_FETCH_OP_AND( , al, "memory")
static inline void __lse_atomic_sub(int i, atomic_t *v) static inline void __lse_atomic_sub(int i, atomic_t *v)
{ {
asm volatile( asm volatile(
__LSE_PREAMBLE
" neg %w[i], %w[i]\n" " neg %w[i], %w[i]\n"
" stadd %w[i], %[v]" " stadd %w[i], %[v]"
: [i] "+&r" (i), [v] "+Q" (v->counter) : [i] "+&r" (i), [v] "+Q" (v->counter)
@ -118,6 +124,7 @@ static inline int __lse_atomic_sub_return##name(int i, atomic_t *v) \
u32 tmp; \ u32 tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" neg %w[i], %w[i]\n" \ " neg %w[i], %w[i]\n" \
" ldadd" #mb " %w[i], %w[tmp], %[v]\n" \ " ldadd" #mb " %w[i], %w[tmp], %[v]\n" \
" add %w[i], %w[i], %w[tmp]" \ " add %w[i], %w[i], %w[tmp]" \
@ -139,6 +146,7 @@ ATOMIC_OP_SUB_RETURN( , al, "memory")
static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v) \ static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" neg %w[i], %w[i]\n" \ " neg %w[i], %w[i]\n" \
" ldadd" #mb " %w[i], %w[i], %[v]" \ " ldadd" #mb " %w[i], %w[i], %[v]" \
: [i] "+&r" (i), [v] "+Q" (v->counter) \ : [i] "+&r" (i), [v] "+Q" (v->counter) \
@ -159,6 +167,7 @@ ATOMIC_FETCH_OP_SUB( , al, "memory")
static inline void __lse_atomic64_##op(s64 i, atomic64_t *v) \ static inline void __lse_atomic64_##op(s64 i, atomic64_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" " #asm_op " %[i], %[v]\n" \ " " #asm_op " %[i], %[v]\n" \
: [i] "+r" (i), [v] "+Q" (v->counter) \ : [i] "+r" (i), [v] "+Q" (v->counter) \
: "r" (v)); \ : "r" (v)); \
@ -175,6 +184,7 @@ ATOMIC64_OP(add, stadd)
static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\ static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" " #asm_op #mb " %[i], %[i], %[v]" \ " " #asm_op #mb " %[i], %[i], %[v]" \
: [i] "+r" (i), [v] "+Q" (v->counter) \ : [i] "+r" (i), [v] "+Q" (v->counter) \
: "r" (v) \ : "r" (v) \
@ -203,6 +213,7 @@ static inline long __lse_atomic64_add_return##name(s64 i, atomic64_t *v)\
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" ldadd" #mb " %[i], %x[tmp], %[v]\n" \ " ldadd" #mb " %[i], %x[tmp], %[v]\n" \
" add %[i], %[i], %x[tmp]" \ " add %[i], %[i], %x[tmp]" \
: [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \
@ -222,6 +233,7 @@ ATOMIC64_OP_ADD_RETURN( , al, "memory")
static inline void __lse_atomic64_and(s64 i, atomic64_t *v) static inline void __lse_atomic64_and(s64 i, atomic64_t *v)
{ {
asm volatile( asm volatile(
__LSE_PREAMBLE
" mvn %[i], %[i]\n" " mvn %[i], %[i]\n"
" stclr %[i], %[v]" " stclr %[i], %[v]"
: [i] "+&r" (i), [v] "+Q" (v->counter) : [i] "+&r" (i), [v] "+Q" (v->counter)
@ -232,6 +244,7 @@ static inline void __lse_atomic64_and(s64 i, atomic64_t *v)
static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \ static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" mvn %[i], %[i]\n" \ " mvn %[i], %[i]\n" \
" ldclr" #mb " %[i], %[i], %[v]" \ " ldclr" #mb " %[i], %[i], %[v]" \
: [i] "+&r" (i), [v] "+Q" (v->counter) \ : [i] "+&r" (i), [v] "+Q" (v->counter) \
@ -251,6 +264,7 @@ ATOMIC64_FETCH_OP_AND( , al, "memory")
static inline void __lse_atomic64_sub(s64 i, atomic64_t *v) static inline void __lse_atomic64_sub(s64 i, atomic64_t *v)
{ {
asm volatile( asm volatile(
__LSE_PREAMBLE
" neg %[i], %[i]\n" " neg %[i], %[i]\n"
" stadd %[i], %[v]" " stadd %[i], %[v]"
: [i] "+&r" (i), [v] "+Q" (v->counter) : [i] "+&r" (i), [v] "+Q" (v->counter)
@ -263,6 +277,7 @@ static inline long __lse_atomic64_sub_return##name(s64 i, atomic64_t *v) \
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" neg %[i], %[i]\n" \ " neg %[i], %[i]\n" \
" ldadd" #mb " %[i], %x[tmp], %[v]\n" \ " ldadd" #mb " %[i], %x[tmp], %[v]\n" \
" add %[i], %[i], %x[tmp]" \ " add %[i], %[i], %x[tmp]" \
@ -284,6 +299,7 @@ ATOMIC64_OP_SUB_RETURN( , al, "memory")
static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \ static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \
{ \ { \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" neg %[i], %[i]\n" \ " neg %[i], %[i]\n" \
" ldadd" #mb " %[i], %[i], %[v]" \ " ldadd" #mb " %[i], %[i], %[v]" \
: [i] "+&r" (i), [v] "+Q" (v->counter) \ : [i] "+&r" (i), [v] "+Q" (v->counter) \
@ -305,6 +321,7 @@ static inline s64 __lse_atomic64_dec_if_positive(atomic64_t *v)
unsigned long tmp; unsigned long tmp;
asm volatile( asm volatile(
__LSE_PREAMBLE
"1: ldr %x[tmp], %[v]\n" "1: ldr %x[tmp], %[v]\n"
" subs %[ret], %x[tmp], #1\n" " subs %[ret], %x[tmp], #1\n"
" b.lt 2f\n" " b.lt 2f\n"
@ -332,6 +349,7 @@ __lse__cmpxchg_case_##name##sz(volatile void *ptr, \
unsigned long tmp; \ unsigned long tmp; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" mov %" #w "[tmp], %" #w "[old]\n" \ " mov %" #w "[tmp], %" #w "[old]\n" \
" cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n" \ " cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n" \
" mov %" #w "[ret], %" #w "[tmp]" \ " mov %" #w "[ret], %" #w "[tmp]" \
@ -379,6 +397,7 @@ __lse__cmpxchg_double##name(unsigned long old1, \
register unsigned long x4 asm ("x4") = (unsigned long)ptr; \ register unsigned long x4 asm ("x4") = (unsigned long)ptr; \
\ \
asm volatile( \ asm volatile( \
__LSE_PREAMBLE \
" casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\ " casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\
" eor %[old1], %[old1], %[oldval1]\n" \ " eor %[old1], %[old1], %[oldval1]\n" \
" eor %[old2], %[old2], %[oldval2]\n" \ " eor %[old2], %[old2], %[oldval2]\n" \

View File

@ -6,6 +6,8 @@
#if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS)
#define __LSE_PREAMBLE ".arch armv8-a+lse\n"
#include <linux/compiler_types.h> #include <linux/compiler_types.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/jump_label.h> #include <linux/jump_label.h>
@ -14,8 +16,6 @@
#include <asm/atomic_lse.h> #include <asm/atomic_lse.h>
#include <asm/cpucaps.h> #include <asm/cpucaps.h>
__asm__(".arch_extension lse");
extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
extern struct static_key_false arm64_const_caps_ready; extern struct static_key_false arm64_const_caps_ready;
@ -34,7 +34,7 @@ static inline bool system_uses_lse_atomics(void)
/* In-line patching at runtime */ /* In-line patching at runtime */
#define ARM64_LSE_ATOMIC_INSN(llsc, lse) \ #define ARM64_LSE_ATOMIC_INSN(llsc, lse) \
ALTERNATIVE(llsc, lse, ARM64_HAS_LSE_ATOMICS) ALTERNATIVE(llsc, __LSE_PREAMBLE lse, ARM64_HAS_LSE_ATOMICS)
#else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ #else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */