2 * Copyright (c) 2013 Andrew Turner <andrew@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #ifndef _MACHINE_ATOMIC_H_
30 #define _MACHINE_ATOMIC_H_
32 #define isb() __asm __volatile("isb" : : : "memory")
35 * Options for DMB and DSB:
36 * oshld Outer Shareable, load
37 * oshst Outer Shareable, store
38 * osh Outer Shareable, all
39 * nshld Non-shareable, load
40 * nshst Non-shareable, store
41 * nsh Non-shareable, all
42 * ishld Inner Shareable, load
43 * ishst Inner Shareable, store
44 * ish Inner Shareable, all
45 * ld Full system, load
46 * st Full system, store
49 #define dsb(opt) __asm __volatile("dsb " __STRING(opt) : : : "memory")
50 #define dmb(opt) __asm __volatile("dmb " __STRING(opt) : : : "memory")
52 #define mb() dmb(sy) /* Full system memory barrier all */
53 #define wmb() dmb(st) /* Full system memory barrier store */
54 #define rmb() dmb(ld) /* Full system memory barrier load */
56 #if defined(KCSAN) && !defined(KCSAN_RUNTIME)
57 #include <sys/_cscan_atomic.h>
60 #include <sys/atomic_common.h>
62 #define ATOMIC_OP(op, asm_op, bar, a, l) \
63 static __inline void \
64 atomic_##op##_##bar##8(volatile uint8_t *p, uint8_t val) \
70 "1: ld"#a"xrb %w0, [%2] \n" \
71 " "#asm_op" %w0, %w0, %w3 \n" \
72 " st"#l"xrb %w1, %w0, [%2] \n" \
74 : "=&r"(tmp), "=&r"(res) \
75 : "r" (p), "r" (val) \
80 static __inline void \
81 atomic_##op##_##bar##16(volatile uint16_t *p, uint16_t val) \
87 "1: ld"#a"xrh %w0, [%2] \n" \
88 " "#asm_op" %w0, %w0, %w3 \n" \
89 " st"#l"xrh %w1, %w0, [%2] \n" \
91 : "=&r"(tmp), "=&r"(res) \
92 : "r" (p), "r" (val) \
97 static __inline void \
98 atomic_##op##_##bar##32(volatile uint32_t *p, uint32_t val) \
104 "1: ld"#a"xr %w0, [%2] \n" \
105 " "#asm_op" %w0, %w0, %w3 \n" \
106 " st"#l"xr %w1, %w0, [%2] \n" \
108 : "=&r"(tmp), "=&r"(res) \
109 : "r" (p), "r" (val) \
114 static __inline void \
115 atomic_##op##_##bar##64(volatile uint64_t *p, uint64_t val) \
121 "1: ld"#a"xr %0, [%2] \n" \
122 " "#asm_op" %0, %0, %3 \n" \
123 " st"#l"xr %w1, %0, [%2] \n" \
125 : "=&r"(tmp), "=&r"(res) \
126 : "r" (p), "r" (val) \
131 #define ATOMIC(op, asm_op) \
132 ATOMIC_OP(op, asm_op, , , ) \
133 ATOMIC_OP(op, asm_op, acq_, a, ) \
134 ATOMIC_OP(op, asm_op, rel_, , l) \
139 ATOMIC(subtract, sub)
141 #define ATOMIC_FCMPSET(bar, a, l) \
142 static __inline int \
143 atomic_fcmpset_##bar##8(volatile uint8_t *p, uint8_t *cmpval, \
147 uint8_t _cmpval = *cmpval; \
151 "1: mov %w1, #1 \n" \
152 " ld"#a"xrb %w0, [%2] \n" \
155 " st"#l"xrb %w1, %w4, [%2]\n" \
157 : "=&r"(tmp), "=&r"(res) \
158 : "r" (p), "r" (_cmpval), "r" (newval) \
166 static __inline int \
167 atomic_fcmpset_##bar##16(volatile uint16_t *p, uint16_t *cmpval, \
171 uint16_t _cmpval = *cmpval; \
175 "1: mov %w1, #1 \n" \
176 " ld"#a"xrh %w0, [%2] \n" \
179 " st"#l"xrh %w1, %w4, [%2] \n" \
181 : "=&r"(tmp), "=&r"(res) \
182 : "r" (p), "r" (_cmpval), "r" (newval) \
190 static __inline int \
191 atomic_fcmpset_##bar##32(volatile uint32_t *p, uint32_t *cmpval, \
195 uint32_t _cmpval = *cmpval; \
199 "1: mov %w1, #1 \n" \
200 " ld"#a"xr %w0, [%2] \n" \
203 " st"#l"xr %w1, %w4, [%2] \n" \
205 : "=&r"(tmp), "=&r"(res) \
206 : "r" (p), "r" (_cmpval), "r" (newval) \
214 static __inline int \
215 atomic_fcmpset_##bar##64(volatile uint64_t *p, uint64_t *cmpval, \
219 uint64_t _cmpval = *cmpval; \
223 "1: mov %w1, #1 \n" \
224 " ld"#a"xr %0, [%2] \n" \
227 " st"#l"xr %w1, %4, [%2] \n" \
229 : "=&r"(tmp), "=&r"(res) \
230 : "r" (p), "r" (_cmpval), "r" (newval) \
238 ATOMIC_FCMPSET( , , )
239 ATOMIC_FCMPSET(acq_, a, )
240 ATOMIC_FCMPSET(rel_, ,l)
242 #undef ATOMIC_FCMPSET
244 #define ATOMIC_CMPSET(bar, a, l) \
245 static __inline int \
246 atomic_cmpset_##bar##8(volatile uint8_t *p, uint8_t cmpval, \
253 "1: mov %w1, #1 \n" \
254 " ld"#a"xrb %w0, [%2] \n" \
257 " st"#l"xrb %w1, %w4, [%2] \n" \
260 : "=&r"(tmp), "=&r"(res) \
261 : "r" (p), "r" (cmpval), "r" (newval) \
268 static __inline int \
269 atomic_cmpset_##bar##16(volatile uint16_t *p, uint16_t cmpval, \
276 "1: mov %w1, #1 \n" \
277 " ld"#a"xrh %w0, [%2] \n" \
280 " st"#l"xrh %w1, %w4, [%2] \n" \
283 : "=&r"(tmp), "=&r"(res) \
284 : "r" (p), "r" (cmpval), "r" (newval) \
291 static __inline int \
292 atomic_cmpset_##bar##32(volatile uint32_t *p, uint32_t cmpval, \
299 "1: mov %w1, #1 \n" \
300 " ld"#a"xr %w0, [%2] \n" \
303 " st"#l"xr %w1, %w4, [%2] \n" \
306 : "=&r"(tmp), "=&r"(res) \
307 : "r" (p), "r" (cmpval), "r" (newval) \
314 static __inline int \
315 atomic_cmpset_##bar##64(volatile uint64_t *p, uint64_t cmpval, \
322 "1: mov %w1, #1 \n" \
323 " ld"#a"xr %0, [%2] \n" \
326 " st"#l"xr %w1, %4, [%2] \n" \
329 : "=&r"(tmp), "=&r"(res) \
330 : "r" (p), "r" (cmpval), "r" (newval) \
338 ATOMIC_CMPSET(acq_, a, )
339 ATOMIC_CMPSET(rel_, ,l)
341 static __inline uint32_t
342 atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
348 "1: ldxr %w2, [%3] \n"
349 " add %w0, %w2, %w4 \n"
350 " stxr %w1, %w0, [%3] \n"
352 : "=&r"(tmp), "=&r"(res), "=&r"(ret)
360 static __inline uint64_t
361 atomic_fetchadd_64(volatile uint64_t *p, uint64_t val)
367 "1: ldxr %2, [%3] \n"
369 " stxr %w1, %0, [%3] \n"
371 : "=&r"(tmp), "=&r"(res), "=&r"(ret)
379 static __inline uint32_t
380 atomic_readandclear_32(volatile uint32_t *p)
386 "1: ldxr %w1, [%2] \n"
387 " stxr %w0, wzr, [%2] \n"
389 : "=&r"(res), "=&r"(ret)
397 static __inline uint64_t
398 atomic_readandclear_64(volatile uint64_t *p)
404 "1: ldxr %1, [%2] \n"
405 " stxr %w0, xzr, [%2] \n"
407 : "=&r"(res), "=&r"(ret)
415 static __inline uint32_t
416 atomic_swap_32(volatile uint32_t *p, uint32_t val)
422 "1: ldxr %w0, [%2] \n"
423 " stxr %w1, %w3, [%2] \n"
425 : "=&r"(ret), "=&r"(res)
433 static __inline uint64_t
434 atomic_swap_64(volatile uint64_t *p, uint64_t val)
440 "1: ldxr %0, [%2] \n"
441 " stxr %w1, %3, [%2] \n"
443 : "=&r"(ret), "=&r"(res)
451 static __inline uint8_t
452 atomic_load_acq_8(volatile uint8_t *p)
465 static __inline uint16_t
466 atomic_load_acq_16(volatile uint16_t *p)
479 static __inline uint32_t
480 atomic_load_acq_32(volatile uint32_t *p)
493 static __inline uint64_t
494 atomic_load_acq_64(volatile uint64_t *p)
508 atomic_store_rel_8(volatile uint8_t *p, uint8_t val)
519 atomic_store_rel_16(volatile uint16_t *p, uint16_t val)
530 atomic_store_rel_32(volatile uint32_t *p, uint32_t val)
541 atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
552 atomic_testandclear_32(volatile uint32_t *p, u_int val)
554 uint32_t mask, old, tmp;
557 mask = 1u << (val & 0x1f);
559 "1: ldxr %w2, [%3] \n"
560 " bic %w0, %w2, %w4 \n"
561 " stxr %w1, %w0, [%3] \n"
563 : "=&r"(tmp), "=&r"(res), "=&r"(old)
564 : "r" (p), "r" (mask)
568 return ((old & mask) != 0);
572 atomic_testandclear_64(volatile uint64_t *p, u_int val)
574 uint64_t mask, old, tmp;
577 mask = 1ul << (val & 0x1f);
579 "1: ldxr %2, [%3] \n"
581 " stxr %w1, %0, [%3] \n"
583 : "=&r"(tmp), "=&r"(res), "=&r"(old)
584 : "r" (p), "r" (mask)
588 return ((old & mask) != 0);
592 atomic_testandset_32(volatile uint32_t *p, u_int val)
594 uint32_t mask, old, tmp;
597 mask = 1u << (val & 0x1f);
599 "1: ldxr %w2, [%3] \n"
600 " orr %w0, %w2, %w4 \n"
601 " stxr %w1, %w0, [%3] \n"
603 : "=&r"(tmp), "=&r"(res), "=&r"(old)
604 : "r" (p), "r" (mask)
608 return ((old & mask) != 0);
612 atomic_testandset_64(volatile uint64_t *p, u_int val)
614 uint64_t mask, old, tmp;
617 mask = 1ul << (val & 0x1f);
619 "1: ldxr %2, [%3] \n"
621 " stxr %w1, %0, [%3] \n"
623 : "=&r"(tmp), "=&r"(res), "=&r"(old)
624 : "r" (p), "r" (mask)
628 return ((old & mask) != 0);
632 #define atomic_add_int atomic_add_32
633 #define atomic_fcmpset_int atomic_fcmpset_32
634 #define atomic_clear_int atomic_clear_32
635 #define atomic_cmpset_int atomic_cmpset_32
636 #define atomic_fetchadd_int atomic_fetchadd_32
637 #define atomic_readandclear_int atomic_readandclear_32
638 #define atomic_set_int atomic_set_32
639 #define atomic_swap_int atomic_swap_32
640 #define atomic_subtract_int atomic_subtract_32
641 #define atomic_testandclear_int atomic_testandclear_32
642 #define atomic_testandset_int atomic_testandset_32
644 #define atomic_add_acq_int atomic_add_acq_32
645 #define atomic_fcmpset_acq_int atomic_fcmpset_acq_32
646 #define atomic_clear_acq_int atomic_clear_acq_32
647 #define atomic_cmpset_acq_int atomic_cmpset_acq_32
648 #define atomic_load_acq_int atomic_load_acq_32
649 #define atomic_set_acq_int atomic_set_acq_32
650 #define atomic_subtract_acq_int atomic_subtract_acq_32
652 #define atomic_add_rel_int atomic_add_rel_32
653 #define atomic_fcmpset_rel_int atomic_fcmpset_rel_32
654 #define atomic_clear_rel_int atomic_clear_rel_32
655 #define atomic_cmpset_rel_int atomic_cmpset_rel_32
656 #define atomic_set_rel_int atomic_set_rel_32
657 #define atomic_subtract_rel_int atomic_subtract_rel_32
658 #define atomic_store_rel_int atomic_store_rel_32
660 #define atomic_add_long atomic_add_64
661 #define atomic_fcmpset_long atomic_fcmpset_64
662 #define atomic_clear_long atomic_clear_64
663 #define atomic_cmpset_long atomic_cmpset_64
664 #define atomic_fetchadd_long atomic_fetchadd_64
665 #define atomic_readandclear_long atomic_readandclear_64
666 #define atomic_set_long atomic_set_64
667 #define atomic_swap_long atomic_swap_64
668 #define atomic_subtract_long atomic_subtract_64
669 #define atomic_testandclear_long atomic_testandclear_64
670 #define atomic_testandset_long atomic_testandset_64
672 #define atomic_add_ptr atomic_add_64
673 #define atomic_fcmpset_ptr atomic_fcmpset_64
674 #define atomic_clear_ptr atomic_clear_64
675 #define atomic_cmpset_ptr atomic_cmpset_64
676 #define atomic_fetchadd_ptr atomic_fetchadd_64
677 #define atomic_readandclear_ptr atomic_readandclear_64
678 #define atomic_set_ptr atomic_set_64
679 #define atomic_swap_ptr atomic_swap_64
680 #define atomic_subtract_ptr atomic_subtract_64
682 #define atomic_add_acq_long atomic_add_acq_64
683 #define atomic_fcmpset_acq_long atomic_fcmpset_acq_64
684 #define atomic_clear_acq_long atomic_clear_acq_64
685 #define atomic_cmpset_acq_long atomic_cmpset_acq_64
686 #define atomic_load_acq_long atomic_load_acq_64
687 #define atomic_set_acq_long atomic_set_acq_64
688 #define atomic_subtract_acq_long atomic_subtract_acq_64
690 #define atomic_add_acq_ptr atomic_add_acq_64
691 #define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_64
692 #define atomic_clear_acq_ptr atomic_clear_acq_64
693 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_64
694 #define atomic_load_acq_ptr atomic_load_acq_64
695 #define atomic_set_acq_ptr atomic_set_acq_64
696 #define atomic_subtract_acq_ptr atomic_subtract_acq_64
698 #define atomic_add_rel_long atomic_add_rel_64
699 #define atomic_fcmpset_rel_long atomic_fcmpset_rel_64
700 #define atomic_clear_rel_long atomic_clear_rel_64
701 #define atomic_cmpset_rel_long atomic_cmpset_rel_64
702 #define atomic_set_rel_long atomic_set_rel_64
703 #define atomic_subtract_rel_long atomic_subtract_rel_64
704 #define atomic_store_rel_long atomic_store_rel_64
706 #define atomic_add_rel_ptr atomic_add_rel_64
707 #define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_64
708 #define atomic_clear_rel_ptr atomic_clear_rel_64
709 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_64
710 #define atomic_set_rel_ptr atomic_set_rel_64
711 #define atomic_subtract_rel_ptr atomic_subtract_rel_64
712 #define atomic_store_rel_ptr atomic_store_rel_64
715 atomic_thread_fence_acq(void)
722 atomic_thread_fence_rel(void)
729 atomic_thread_fence_acq_rel(void)
736 atomic_thread_fence_seq_cst(void)
742 #endif /* KCSAN && !KCSAN_RUNTIME */
744 #endif /* _MACHINE_ATOMIC_H_ */