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
9*0cc3a351SSean Christopherson #ifndef __ASSEMBLER__
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)
361721daedSAndrew Jones #define check_sub_overflow(a, b) __builtin_sub_overflow_p(a, b, (typeof((a) - (b)))0)
371721daedSAndrew Jones #define check_mul_overflow(a, b) __builtin_mul_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
48b0fcca88SNicholas Piggin /*
49b0fcca88SNicholas Piggin * As glibc's sys/cdefs.h does, this undefines __always_inline because
50b0fcca88SNicholas Piggin * Linux's stddef.h kernel header also defines it in an incompatible
51b0fcca88SNicholas Piggin * way.
52b0fcca88SNicholas Piggin */
53b0fcca88SNicholas Piggin #undef __always_inline
54b0fcca88SNicholas Piggin #define __always_inline __inline __attribute__ ((__always_inline__))
55b0fcca88SNicholas Piggin
5616431a73SBill Wendling #define noinline __attribute__((noinline))
57a9d450afSSean Christopherson #define __unused __attribute__((__unused__))
58d5b60621SAlexandru Elisei
__read_once_size(const volatile void * p,void * res,int size)59d5b60621SAlexandru Elisei static __always_inline void __read_once_size(const volatile void *p, void *res, int size)
60d5b60621SAlexandru Elisei {
61d5b60621SAlexandru Elisei switch (size) {
62d5b60621SAlexandru Elisei case 1: *(uint8_t *)res = *(volatile uint8_t *)p; break;
63d5b60621SAlexandru Elisei case 2: *(uint16_t *)res = *(volatile uint16_t *)p; break;
64d5b60621SAlexandru Elisei case 4: *(uint32_t *)res = *(volatile uint32_t *)p; break;
65d5b60621SAlexandru Elisei case 8: *(uint64_t *)res = *(volatile uint64_t *)p; break;
66d5b60621SAlexandru Elisei default:
67d5b60621SAlexandru Elisei barrier();
68d5b60621SAlexandru Elisei __builtin_memcpy((void *)res, (const void *)p, size);
69d5b60621SAlexandru Elisei barrier();
70d5b60621SAlexandru Elisei }
71d5b60621SAlexandru Elisei }
72d5b60621SAlexandru Elisei
73d5b60621SAlexandru Elisei /*
74d5b60621SAlexandru Elisei * Prevent the compiler from merging or refetching reads or writes. The
75d5b60621SAlexandru Elisei * compiler is also forbidden from reordering successive instances of
76d5b60621SAlexandru Elisei * READ_ONCE and WRITE_ONCE, but only when the compiler is aware of some
77d5b60621SAlexandru Elisei * particular ordering. One way to make the compiler aware of ordering is to
78d5b60621SAlexandru Elisei * put the two invocations of READ_ONCE or WRITE_ONCE in different C
79d5b60621SAlexandru Elisei * statements.
80d5b60621SAlexandru Elisei *
81d5b60621SAlexandru Elisei * These two macros will also work on aggregate data types like structs or
82d5b60621SAlexandru Elisei * unions. If the size of the accessed data type exceeds the word size of
83d5b60621SAlexandru Elisei * the machine (e.g., 32 bits or 64 bits) READ_ONCE() and WRITE_ONCE() will
84d5b60621SAlexandru Elisei * fall back to memcpy and print a compile-time warning.
85d5b60621SAlexandru Elisei *
86d5b60621SAlexandru Elisei * Their two major use cases are: (1) Mediating communication between
87d5b60621SAlexandru Elisei * process-level code and irq/NMI handlers, all running on the same CPU,
88d5b60621SAlexandru Elisei * and (2) Ensuring that the compiler does not fold, spindle, or otherwise
89d5b60621SAlexandru Elisei * mutilate accesses that either do not require ordering or that interact
90d5b60621SAlexandru Elisei * with an explicit memory barrier or atomic instruction that provides the
91d5b60621SAlexandru Elisei * required ordering.
92d5b60621SAlexandru Elisei */
93d5b60621SAlexandru Elisei
94d5b60621SAlexandru Elisei #define READ_ONCE(x) \
95d5b60621SAlexandru Elisei ({ \
96d5b60621SAlexandru Elisei union { typeof(x) __val; char __c[1]; } __u = \
97d5b60621SAlexandru Elisei { .__c = { 0 } }; \
98d5b60621SAlexandru Elisei __read_once_size(&(x), __u.__c, sizeof(x)); \
99d5b60621SAlexandru Elisei __u.__val; \
100d5b60621SAlexandru Elisei })
101d5b60621SAlexandru Elisei
__write_once_size(volatile void * p,void * res,int size)102d5b60621SAlexandru Elisei static __always_inline void __write_once_size(volatile void *p, void *res, int size)
103d5b60621SAlexandru Elisei {
104d5b60621SAlexandru Elisei switch (size) {
105d5b60621SAlexandru Elisei case 1: *(volatile uint8_t *) p = *(uint8_t *) res; break;
106d5b60621SAlexandru Elisei case 2: *(volatile uint16_t *) p = *(uint16_t *) res; break;
107d5b60621SAlexandru Elisei case 4: *(volatile uint32_t *) p = *(uint32_t *) res; break;
108d5b60621SAlexandru Elisei case 8: *(volatile uint64_t *) p = *(uint64_t *) res; break;
109d5b60621SAlexandru Elisei default:
110d5b60621SAlexandru Elisei barrier();
111d5b60621SAlexandru Elisei __builtin_memcpy((void *)p, (const void *)res, size);
112d5b60621SAlexandru Elisei barrier();
113d5b60621SAlexandru Elisei }
114d5b60621SAlexandru Elisei }
115d5b60621SAlexandru Elisei
116d5b60621SAlexandru Elisei #define WRITE_ONCE(x, val) \
117d5b60621SAlexandru Elisei ({ \
118d5b60621SAlexandru Elisei union { typeof(x) __val; char __c[1]; } __u = \
119d5b60621SAlexandru Elisei { .__val = (val) }; \
120d5b60621SAlexandru Elisei __write_once_size(&(x), __u.__c, sizeof(x)); \
121d5b60621SAlexandru Elisei __u.__val; \
122d5b60621SAlexandru Elisei })
123d5b60621SAlexandru Elisei
124*0cc3a351SSean Christopherson #endif /* !__ASSEMBLER__ */
125d5b60621SAlexandru Elisei #endif /* !__LINUX_COMPILER_H */
126