1d5b60621SAlexandru Elisei /* SPDX-License-Identifier: GPL-2.0 */ 2d5b60621SAlexandru Elisei /* 3d5b60621SAlexandru Elisei * Taken from Linux commit 219d54332a09 ("Linux 5.4"), from the file 4d5b60621SAlexandru Elisei * tools/include/linux/compiler.h, with minor changes. 5d5b60621SAlexandru Elisei */ 6d5b60621SAlexandru Elisei #ifndef __LINUX_COMPILER_H 7d5b60621SAlexandru Elisei #define __LINUX_COMPILER_H 8d5b60621SAlexandru Elisei 9d5b60621SAlexandru Elisei #ifndef __ASSEMBLY__ 10d5b60621SAlexandru Elisei 114ceb02bfSAndrew Jones #define GCC_VERSION (__GNUC__ * 10000 \ 124ceb02bfSAndrew Jones + __GNUC_MINOR__ * 100 \ 134ceb02bfSAndrew Jones + __GNUC_PATCHLEVEL__) 144ceb02bfSAndrew Jones 154ceb02bfSAndrew Jones #ifdef __clang__ 164ceb02bfSAndrew Jones #if __has_builtin(__builtin_add_overflow) && \ 174ceb02bfSAndrew Jones __has_builtin(__builtin_sub_overflow) && \ 184ceb02bfSAndrew Jones __has_builtin(__builtin_mul_overflow) 194ceb02bfSAndrew Jones #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 204ceb02bfSAndrew Jones #define check_add_overflow(a, b) ({ \ 214ceb02bfSAndrew Jones typeof((a) + (b)) __d; \ 224ceb02bfSAndrew Jones __builtin_add_overflow(a, b, &__d); \ 234ceb02bfSAndrew Jones }) 244ceb02bfSAndrew Jones #define check_sub_overflow(a, b) ({ \ 254ceb02bfSAndrew Jones typeof((a) - (b)) __d; \ 264ceb02bfSAndrew Jones __builtin_sub_overflow(a, b, &__d); \ 274ceb02bfSAndrew Jones }) 284ceb02bfSAndrew Jones #define check_mul_overflow(a, b) ({ \ 294ceb02bfSAndrew Jones typeof((a) * (b)) __d; \ 304ceb02bfSAndrew Jones __builtin_mul_overflow(a, b, &__d); \ 314ceb02bfSAndrew Jones }) 324ceb02bfSAndrew Jones #endif 3353017303SPo-Hsu Lin #elif GCC_VERSION >= 70100 344ceb02bfSAndrew Jones #define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 354ceb02bfSAndrew Jones #define check_add_overflow(a, b) __builtin_add_overflow_p(a, b, (typeof((a) + (b)))0) 364ceb02bfSAndrew Jones #define check_sub_overflow(a, b) __builtin_add_overflow_p(a, b, (typeof((a) - (b)))0) 374ceb02bfSAndrew Jones #define check_mul_overflow(a, b) __builtin_add_overflow_p(a, b, (typeof((a) * (b)))0) 384ceb02bfSAndrew Jones #else 394ceb02bfSAndrew Jones #define check_add_overflow(a, b) ({ (void)((int)(a) == (int)(b)); 0; }) 404ceb02bfSAndrew Jones #define check_sub_overflow(a, b) ({ (void)((int)(a) == (int)(b)); 0; }) 414ceb02bfSAndrew Jones #define check_mul_overflow(a, b) ({ (void)((int)(a) == (int)(b)); 0; }) 424ceb02bfSAndrew Jones #endif 434ceb02bfSAndrew Jones 44d5b60621SAlexandru Elisei #include <stdint.h> 45d5b60621SAlexandru Elisei 46d5b60621SAlexandru Elisei #define barrier() asm volatile("" : : : "memory") 47d5b60621SAlexandru Elisei 48d5b60621SAlexandru Elisei #define __always_inline inline __attribute__((always_inline)) 4916431a73SBill Wendling #define noinline __attribute__((noinline)) 50*a9d450afSSean Christopherson #define __unused __attribute__((__unused__)) 51d5b60621SAlexandru Elisei 52d5b60621SAlexandru Elisei static __always_inline void __read_once_size(const volatile void *p, void *res, int size) 53d5b60621SAlexandru Elisei { 54d5b60621SAlexandru Elisei switch (size) { 55d5b60621SAlexandru Elisei case 1: *(uint8_t *)res = *(volatile uint8_t *)p; break; 56d5b60621SAlexandru Elisei case 2: *(uint16_t *)res = *(volatile uint16_t *)p; break; 57d5b60621SAlexandru Elisei case 4: *(uint32_t *)res = *(volatile uint32_t *)p; break; 58d5b60621SAlexandru Elisei case 8: *(uint64_t *)res = *(volatile uint64_t *)p; break; 59d5b60621SAlexandru Elisei default: 60d5b60621SAlexandru Elisei barrier(); 61d5b60621SAlexandru Elisei __builtin_memcpy((void *)res, (const void *)p, size); 62d5b60621SAlexandru Elisei barrier(); 63d5b60621SAlexandru Elisei } 64d5b60621SAlexandru Elisei } 65d5b60621SAlexandru Elisei 66d5b60621SAlexandru Elisei /* 67d5b60621SAlexandru Elisei * Prevent the compiler from merging or refetching reads or writes. The 68d5b60621SAlexandru Elisei * compiler is also forbidden from reordering successive instances of 69d5b60621SAlexandru Elisei * READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some 70d5b60621SAlexandru Elisei * particular ordering. One way to make the compiler aware of ordering is to 71d5b60621SAlexandru Elisei * put the two invocations of READ_ONCE or WRITE_ONCE in different C 72d5b60621SAlexandru Elisei * statements. 73d5b60621SAlexandru Elisei * 74d5b60621SAlexandru Elisei * These two macros will also work on aggregate data types like structs or 75d5b60621SAlexandru Elisei * unions. If the size of the accessed data type exceeds the word size of 76d5b60621SAlexandru Elisei * the machine (e.g., 32 bits or 64 bits) READ_ONCE() and WRITE_ONCE() will 77d5b60621SAlexandru Elisei * fall back to memcpy and print a compile-time warning. 78d5b60621SAlexandru Elisei * 79d5b60621SAlexandru Elisei * Their two major use cases are: (1) Mediating communication between 80d5b60621SAlexandru Elisei * process-level code and irq/NMI handlers, all running on the same CPU, 81d5b60621SAlexandru Elisei * and (2) Ensuring that the compiler does not fold, spindle, or otherwise 82d5b60621SAlexandru Elisei * mutilate accesses that either do not require ordering or that interact 83d5b60621SAlexandru Elisei * with an explicit memory barrier or atomic instruction that provides the 84d5b60621SAlexandru Elisei * required ordering. 85d5b60621SAlexandru Elisei */ 86d5b60621SAlexandru Elisei 87d5b60621SAlexandru Elisei #define READ_ONCE(x) \ 88d5b60621SAlexandru Elisei ({ \ 89d5b60621SAlexandru Elisei union { typeof(x) __val; char __c[1]; } __u = \ 90d5b60621SAlexandru Elisei { .__c = { 0 } }; \ 91d5b60621SAlexandru Elisei __read_once_size(&(x), __u.__c, sizeof(x)); \ 92d5b60621SAlexandru Elisei __u.__val; \ 93d5b60621SAlexandru Elisei }) 94d5b60621SAlexandru Elisei 95d5b60621SAlexandru Elisei static __always_inline void __write_once_size(volatile void *p, void *res, int size) 96d5b60621SAlexandru Elisei { 97d5b60621SAlexandru Elisei switch (size) { 98d5b60621SAlexandru Elisei case 1: *(volatile uint8_t *) p = *(uint8_t *) res; break; 99d5b60621SAlexandru Elisei case 2: *(volatile uint16_t *) p = *(uint16_t *) res; break; 100d5b60621SAlexandru Elisei case 4: *(volatile uint32_t *) p = *(uint32_t *) res; break; 101d5b60621SAlexandru Elisei case 8: *(volatile uint64_t *) p = *(uint64_t *) res; break; 102d5b60621SAlexandru Elisei default: 103d5b60621SAlexandru Elisei barrier(); 104d5b60621SAlexandru Elisei __builtin_memcpy((void *)p, (const void *)res, size); 105d5b60621SAlexandru Elisei barrier(); 106d5b60621SAlexandru Elisei } 107d5b60621SAlexandru Elisei } 108d5b60621SAlexandru Elisei 109d5b60621SAlexandru Elisei #define WRITE_ONCE(x, val) \ 110d5b60621SAlexandru Elisei ({ \ 111d5b60621SAlexandru Elisei union { typeof(x) __val; char __c[1]; } __u = \ 112d5b60621SAlexandru Elisei { .__val = (val) }; \ 113d5b60621SAlexandru Elisei __write_once_size(&(x), __u.__c, sizeof(x)); \ 114d5b60621SAlexandru Elisei __u.__val; \ 115d5b60621SAlexandru Elisei }) 116d5b60621SAlexandru Elisei 117d5b60621SAlexandru Elisei #endif /* !__ASSEMBLY__ */ 118d5b60621SAlexandru Elisei #endif /* !__LINUX_COMPILER_H */ 119