Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

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>

authored by

Sami Tolvanen and committed by
Will Deacon
e0d5896b 46cf053e

+22 -3
+19
arch/arm64/include/asm/atomic_lse.h
··· 14 14 static inline void __lse_atomic_##op(int i, atomic_t *v) \ 15 15 { \ 16 16 asm volatile( \ 17 + __LSE_PREAMBLE \ 17 18 " " #asm_op " %w[i], %[v]\n" \ 18 19 : [i] "+r" (i), [v] "+Q" (v->counter) \ 19 20 : "r" (v)); \ ··· 31 30 static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v) \ 32 31 { \ 33 32 asm volatile( \ 33 + __LSE_PREAMBLE \ 34 34 " " #asm_op #mb " %w[i], %w[i], %[v]" \ 35 35 : [i] "+r" (i), [v] "+Q" (v->counter) \ 36 36 : "r" (v) \ ··· 60 58 u32 tmp; \ 61 59 \ 62 60 asm volatile( \ 61 + __LSE_PREAMBLE \ 63 62 " ldadd" #mb " %w[i], %w[tmp], %[v]\n" \ 64 63 " add %w[i], %w[i], %w[tmp]" \ 65 64 : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ ··· 80 77 static inline void __lse_atomic_and(int i, atomic_t *v) 81 78 { 82 79 asm volatile( 80 + __LSE_PREAMBLE 83 81 " mvn %w[i], %w[i]\n" 84 82 " stclr %w[i], %[v]" 85 83 : [i] "+&r" (i), [v] "+Q" (v->counter) ··· 91 87 static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v) \ 92 88 { \ 93 89 asm volatile( \ 90 + __LSE_PREAMBLE \ 94 91 " mvn %w[i], %w[i]\n" \ 95 92 " ldclr" #mb " %w[i], %w[i], %[v]" \ 96 93 : [i] "+&r" (i), [v] "+Q" (v->counter) \ ··· 111 106 static inline void __lse_atomic_sub(int i, atomic_t *v) 112 107 { 113 108 asm volatile( 109 + __LSE_PREAMBLE 114 110 " neg %w[i], %w[i]\n" 115 111 " stadd %w[i], %[v]" 116 112 : [i] "+&r" (i), [v] "+Q" (v->counter) ··· 124 118 u32 tmp; \ 125 119 \ 126 120 asm volatile( \ 121 + __LSE_PREAMBLE \ 127 122 " neg %w[i], %w[i]\n" \ 128 123 " ldadd" #mb " %w[i], %w[tmp], %[v]\n" \ 129 124 " add %w[i], %w[i], %w[tmp]" \ ··· 146 139 static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v) \ 147 140 { \ 148 141 asm volatile( \ 142 + __LSE_PREAMBLE \ 149 143 " neg %w[i], %w[i]\n" \ 150 144 " ldadd" #mb " %w[i], %w[i], %[v]" \ 151 145 : [i] "+&r" (i), [v] "+Q" (v->counter) \ ··· 167 159 static inline void __lse_atomic64_##op(s64 i, atomic64_t *v) \ 168 160 { \ 169 161 asm volatile( \ 162 + __LSE_PREAMBLE \ 170 163 " " #asm_op " %[i], %[v]\n" \ 171 164 : [i] "+r" (i), [v] "+Q" (v->counter) \ 172 165 : "r" (v)); \ ··· 184 175 static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\ 185 176 { \ 186 177 asm volatile( \ 178 + __LSE_PREAMBLE \ 187 179 " " #asm_op #mb " %[i], %[i], %[v]" \ 188 180 : [i] "+r" (i), [v] "+Q" (v->counter) \ 189 181 : "r" (v) \ ··· 213 203 unsigned long tmp; \ 214 204 \ 215 205 asm volatile( \ 206 + __LSE_PREAMBLE \ 216 207 " ldadd" #mb " %[i], %x[tmp], %[v]\n" \ 217 208 " add %[i], %[i], %x[tmp]" \ 218 209 : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp) \ ··· 233 222 static inline void __lse_atomic64_and(s64 i, atomic64_t *v) 234 223 { 235 224 asm volatile( 225 + __LSE_PREAMBLE 236 226 " mvn %[i], %[i]\n" 237 227 " stclr %[i], %[v]" 238 228 : [i] "+&r" (i), [v] "+Q" (v->counter) ··· 244 232 static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \ 245 233 { \ 246 234 asm volatile( \ 235 + __LSE_PREAMBLE \ 247 236 " mvn %[i], %[i]\n" \ 248 237 " ldclr" #mb " %[i], %[i], %[v]" \ 249 238 : [i] "+&r" (i), [v] "+Q" (v->counter) \ ··· 264 251 static inline void __lse_atomic64_sub(s64 i, atomic64_t *v) 265 252 { 266 253 asm volatile( 254 + __LSE_PREAMBLE 267 255 " neg %[i], %[i]\n" 268 256 " stadd %[i], %[v]" 269 257 : [i] "+&r" (i), [v] "+Q" (v->counter) ··· 277 263 unsigned long tmp; \ 278 264 \ 279 265 asm volatile( \ 266 + __LSE_PREAMBLE \ 280 267 " neg %[i], %[i]\n" \ 281 268 " ldadd" #mb " %[i], %x[tmp], %[v]\n" \ 282 269 " add %[i], %[i], %x[tmp]" \ ··· 299 284 static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \ 300 285 { \ 301 286 asm volatile( \ 287 + __LSE_PREAMBLE \ 302 288 " neg %[i], %[i]\n" \ 303 289 " ldadd" #mb " %[i], %[i], %[v]" \ 304 290 : [i] "+&r" (i), [v] "+Q" (v->counter) \ ··· 321 305 unsigned long tmp; 322 306 323 307 asm volatile( 308 + __LSE_PREAMBLE 324 309 "1: ldr %x[tmp], %[v]\n" 325 310 " subs %[ret], %x[tmp], #1\n" 326 311 " b.lt 2f\n" ··· 349 332 unsigned long tmp; \ 350 333 \ 351 334 asm volatile( \ 335 + __LSE_PREAMBLE \ 352 336 " mov %" #w "[tmp], %" #w "[old]\n" \ 353 337 " cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n" \ 354 338 " mov %" #w "[ret], %" #w "[tmp]" \ ··· 397 379 register unsigned long x4 asm ("x4") = (unsigned long)ptr; \ 398 380 \ 399 381 asm volatile( \ 382 + __LSE_PREAMBLE \ 400 383 " casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\ 401 384 " eor %[old1], %[old1], %[oldval1]\n" \ 402 385 " eor %[old2], %[old2], %[oldval2]\n" \
+3 -3
arch/arm64/include/asm/lse.h
··· 6 6 7 7 #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) 8 8 9 + #define __LSE_PREAMBLE ".arch armv8-a+lse\n" 10 + 9 11 #include <linux/compiler_types.h> 10 12 #include <linux/export.h> 11 13 #include <linux/jump_label.h> ··· 15 13 #include <asm/alternative.h> 16 14 #include <asm/atomic_lse.h> 17 15 #include <asm/cpucaps.h> 18 - 19 - __asm__(".arch_extension lse"); 20 16 21 17 extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; 22 18 extern struct static_key_false arm64_const_caps_ready; ··· 34 34 35 35 /* In-line patching at runtime */ 36 36 #define ARM64_LSE_ATOMIC_INSN(llsc, lse) \ 37 - ALTERNATIVE(llsc, lse, ARM64_HAS_LSE_ATOMICS) 37 + ALTERNATIVE(llsc, __LSE_PREAMBLE lse, ARM64_HAS_LSE_ATOMICS) 38 38 39 39 #else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ 40 40