1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * Copyright (C) 2020 Google LLC. 4 */ 5 #ifndef __ASM_RWONCE_H 6 #define __ASM_RWONCE_H 7 8 #ifdef CONFIG_LTO 9 10 #include <linux/compiler_types.h> 11 #include <asm/alternative-macros.h> 12 13 #ifndef BUILD_VDSO 14 15 #ifdef CONFIG_AS_HAS_LDAPR 16 #define __LOAD_RCPC(sfx, regs...) \ 17 ALTERNATIVE( \ 18 "ldar" #sfx "\t" #regs, \ 19 ".arch_extension rcpc\n" \ 20 "ldapr" #sfx "\t" #regs, \ 21 ARM64_HAS_LDAPR) 22 #else 23 #define __LOAD_RCPC(sfx, regs...) "ldar" #sfx "\t" #regs 24 #endif /* CONFIG_AS_HAS_LDAPR */ 25 26 /* 27 * When building with LTO, there is an increased risk of the compiler 28 * converting an address dependency headed by a READ_ONCE() invocation 29 * into a control dependency and consequently allowing for harmful 30 * reordering by the CPU. 31 * 32 * Ensure that such transformations are harmless by overriding the generic 33 * READ_ONCE() definition with one that provides RCpc acquire semantics 34 * when building with LTO. 35 */ 36 #define __READ_ONCE(x) \ 37 ({ \ 38 typeof(&(x)) __x = &(x); \ 39 int atomic = 1; \ 40 union { __unqual_scalar_typeof(*__x) __val; char __c[1]; } __u; \ 41 switch (sizeof(x)) { \ 42 case 1: \ 43 asm volatile(__LOAD_RCPC(b, %w0, %1) \ 44 : "=r" (*(__u8 *)__u.__c) \ 45 : "Q" (*__x) : "memory"); \ 46 break; \ 47 case 2: \ 48 asm volatile(__LOAD_RCPC(h, %w0, %1) \ 49 : "=r" (*(__u16 *)__u.__c) \ 50 : "Q" (*__x) : "memory"); \ 51 break; \ 52 case 4: \ 53 asm volatile(__LOAD_RCPC(, %w0, %1) \ 54 : "=r" (*(__u32 *)__u.__c) \ 55 : "Q" (*__x) : "memory"); \ 56 break; \ 57 case 8: \ 58 asm volatile(__LOAD_RCPC(, %0, %1) \ 59 : "=r" (*(__u64 *)__u.__c) \ 60 : "Q" (*__x) : "memory"); \ 61 break; \ 62 default: \ 63 atomic = 0; \ 64 } \ 65 atomic ? (typeof(*__x))__u.__val : (*(volatile typeof(__x))__x);\ 66 }) 67 68 #endif /* !BUILD_VDSO */ 69 #endif /* CONFIG_LTO */ 70 71 #include <asm-generic/rwonce.h> 72 73 #endif /* __ASM_RWONCE_H */ 74