xref: /openbmc/linux/include/asm-generic/bitops/instrumented-non-atomic.h (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
181d2c6f8SDaniel Axtens /* SPDX-License-Identifier: GPL-2.0 */
281d2c6f8SDaniel Axtens 
381d2c6f8SDaniel Axtens /*
481d2c6f8SDaniel Axtens  * This file provides wrappers with sanitizer instrumentation for non-atomic
581d2c6f8SDaniel Axtens  * bit operations.
681d2c6f8SDaniel Axtens  *
781d2c6f8SDaniel Axtens  * To use this functionality, an arch's bitops.h file needs to define each of
881d2c6f8SDaniel Axtens  * the below bit operations with an arch_ prefix (e.g. arch_set_bit(),
981d2c6f8SDaniel Axtens  * arch___set_bit(), etc.).
1081d2c6f8SDaniel Axtens  */
1181d2c6f8SDaniel Axtens #ifndef _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H
1281d2c6f8SDaniel Axtens #define _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H
1381d2c6f8SDaniel Axtens 
1427f937ccSMarco Elver #include <linux/instrumented.h>
1581d2c6f8SDaniel Axtens 
1681d2c6f8SDaniel Axtens /**
17e69eb9c4SAlexander Lobakin  * ___set_bit - Set a bit in memory
1881d2c6f8SDaniel Axtens  * @nr: the bit to set
1981d2c6f8SDaniel Axtens  * @addr: the address to start counting from
2081d2c6f8SDaniel Axtens  *
2181d2c6f8SDaniel Axtens  * Unlike set_bit(), this function is non-atomic. If it is called on the same
2281d2c6f8SDaniel Axtens  * region of memory concurrently, the effect may be that only one operation
2381d2c6f8SDaniel Axtens  * succeeds.
2481d2c6f8SDaniel Axtens  */
250e862838SAlexander Lobakin static __always_inline void
___set_bit(unsigned long nr,volatile unsigned long * addr)26e69eb9c4SAlexander Lobakin ___set_bit(unsigned long nr, volatile unsigned long *addr)
2781d2c6f8SDaniel Axtens {
2827f937ccSMarco Elver 	instrument_write(addr + BIT_WORD(nr), sizeof(long));
2981d2c6f8SDaniel Axtens 	arch___set_bit(nr, addr);
3081d2c6f8SDaniel Axtens }
3181d2c6f8SDaniel Axtens 
3281d2c6f8SDaniel Axtens /**
33e69eb9c4SAlexander Lobakin  * ___clear_bit - Clears a bit in memory
3481d2c6f8SDaniel Axtens  * @nr: the bit to clear
3581d2c6f8SDaniel Axtens  * @addr: the address to start counting from
3681d2c6f8SDaniel Axtens  *
3781d2c6f8SDaniel Axtens  * Unlike clear_bit(), this function is non-atomic. If it is called on the same
3881d2c6f8SDaniel Axtens  * region of memory concurrently, the effect may be that only one operation
3981d2c6f8SDaniel Axtens  * succeeds.
4081d2c6f8SDaniel Axtens  */
410e862838SAlexander Lobakin static __always_inline void
___clear_bit(unsigned long nr,volatile unsigned long * addr)42e69eb9c4SAlexander Lobakin ___clear_bit(unsigned long nr, volatile unsigned long *addr)
4381d2c6f8SDaniel Axtens {
4427f937ccSMarco Elver 	instrument_write(addr + BIT_WORD(nr), sizeof(long));
4581d2c6f8SDaniel Axtens 	arch___clear_bit(nr, addr);
4681d2c6f8SDaniel Axtens }
4781d2c6f8SDaniel Axtens 
4881d2c6f8SDaniel Axtens /**
49e69eb9c4SAlexander Lobakin  * ___change_bit - Toggle a bit in memory
5081d2c6f8SDaniel Axtens  * @nr: the bit to change
5181d2c6f8SDaniel Axtens  * @addr: the address to start counting from
5281d2c6f8SDaniel Axtens  *
5381d2c6f8SDaniel Axtens  * Unlike change_bit(), this function is non-atomic. If it is called on the same
5481d2c6f8SDaniel Axtens  * region of memory concurrently, the effect may be that only one operation
5581d2c6f8SDaniel Axtens  * succeeds.
5681d2c6f8SDaniel Axtens  */
570e862838SAlexander Lobakin static __always_inline void
___change_bit(unsigned long nr,volatile unsigned long * addr)58e69eb9c4SAlexander Lobakin ___change_bit(unsigned long nr, volatile unsigned long *addr)
5981d2c6f8SDaniel Axtens {
6027f937ccSMarco Elver 	instrument_write(addr + BIT_WORD(nr), sizeof(long));
6181d2c6f8SDaniel Axtens 	arch___change_bit(nr, addr);
6281d2c6f8SDaniel Axtens }
6381d2c6f8SDaniel Axtens 
__instrument_read_write_bitop(long nr,volatile unsigned long * addr)64acb13ea0SBorislav Petkov static __always_inline void __instrument_read_write_bitop(long nr, volatile unsigned long *addr)
65068df053SMarco Elver {
66068df053SMarco Elver 	if (IS_ENABLED(CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC)) {
67068df053SMarco Elver 		/*
68068df053SMarco Elver 		 * We treat non-atomic read-write bitops a little more special.
69068df053SMarco Elver 		 * Given the operations here only modify a single bit, assuming
70068df053SMarco Elver 		 * non-atomicity of the writer is sufficient may be reasonable
71068df053SMarco Elver 		 * for certain usage (and follows the permissible nature of the
72068df053SMarco Elver 		 * assume-plain-writes-atomic rule):
73068df053SMarco Elver 		 * 1. report read-modify-write races -> check read;
74068df053SMarco Elver 		 * 2. do not report races with marked readers, but do report
75068df053SMarco Elver 		 *    races with unmarked readers -> check "atomic" write.
76068df053SMarco Elver 		 */
77068df053SMarco Elver 		kcsan_check_read(addr + BIT_WORD(nr), sizeof(long));
78068df053SMarco Elver 		/*
79068df053SMarco Elver 		 * Use generic write instrumentation, in case other sanitizers
80068df053SMarco Elver 		 * or tools are enabled alongside KCSAN.
81068df053SMarco Elver 		 */
82068df053SMarco Elver 		instrument_write(addr + BIT_WORD(nr), sizeof(long));
83068df053SMarco Elver 	} else {
84068df053SMarco Elver 		instrument_read_write(addr + BIT_WORD(nr), sizeof(long));
85068df053SMarco Elver 	}
86068df053SMarco Elver }
87068df053SMarco Elver 
8881d2c6f8SDaniel Axtens /**
89e69eb9c4SAlexander Lobakin  * ___test_and_set_bit - Set a bit and return its old value
9081d2c6f8SDaniel Axtens  * @nr: Bit to set
9181d2c6f8SDaniel Axtens  * @addr: Address to count from
9281d2c6f8SDaniel Axtens  *
9381d2c6f8SDaniel Axtens  * This operation is non-atomic. If two instances of this operation race, one
9481d2c6f8SDaniel Axtens  * can appear to succeed but actually fail.
9581d2c6f8SDaniel Axtens  */
960e862838SAlexander Lobakin static __always_inline bool
___test_and_set_bit(unsigned long nr,volatile unsigned long * addr)97e69eb9c4SAlexander Lobakin ___test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
9881d2c6f8SDaniel Axtens {
99068df053SMarco Elver 	__instrument_read_write_bitop(nr, addr);
10081d2c6f8SDaniel Axtens 	return arch___test_and_set_bit(nr, addr);
10181d2c6f8SDaniel Axtens }
10281d2c6f8SDaniel Axtens 
10381d2c6f8SDaniel Axtens /**
104e69eb9c4SAlexander Lobakin  * ___test_and_clear_bit - Clear a bit and return its old value
10581d2c6f8SDaniel Axtens  * @nr: Bit to clear
10681d2c6f8SDaniel Axtens  * @addr: Address to count from
10781d2c6f8SDaniel Axtens  *
10881d2c6f8SDaniel Axtens  * This operation is non-atomic. If two instances of this operation race, one
10981d2c6f8SDaniel Axtens  * can appear to succeed but actually fail.
11081d2c6f8SDaniel Axtens  */
1110e862838SAlexander Lobakin static __always_inline bool
___test_and_clear_bit(unsigned long nr,volatile unsigned long * addr)112e69eb9c4SAlexander Lobakin ___test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
11381d2c6f8SDaniel Axtens {
114068df053SMarco Elver 	__instrument_read_write_bitop(nr, addr);
11581d2c6f8SDaniel Axtens 	return arch___test_and_clear_bit(nr, addr);
11681d2c6f8SDaniel Axtens }
11781d2c6f8SDaniel Axtens 
11881d2c6f8SDaniel Axtens /**
119e69eb9c4SAlexander Lobakin  * ___test_and_change_bit - Change a bit and return its old value
12081d2c6f8SDaniel Axtens  * @nr: Bit to change
12181d2c6f8SDaniel Axtens  * @addr: Address to count from
12281d2c6f8SDaniel Axtens  *
12381d2c6f8SDaniel Axtens  * This operation is non-atomic. If two instances of this operation race, one
12481d2c6f8SDaniel Axtens  * can appear to succeed but actually fail.
12581d2c6f8SDaniel Axtens  */
1260e862838SAlexander Lobakin static __always_inline bool
___test_and_change_bit(unsigned long nr,volatile unsigned long * addr)127e69eb9c4SAlexander Lobakin ___test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
12881d2c6f8SDaniel Axtens {
129068df053SMarco Elver 	__instrument_read_write_bitop(nr, addr);
13081d2c6f8SDaniel Axtens 	return arch___test_and_change_bit(nr, addr);
13181d2c6f8SDaniel Axtens }
13281d2c6f8SDaniel Axtens 
13381d2c6f8SDaniel Axtens /**
134e69eb9c4SAlexander Lobakin  * _test_bit - Determine whether a bit is set
13581d2c6f8SDaniel Axtens  * @nr: bit number to test
13681d2c6f8SDaniel Axtens  * @addr: Address to start counting from
13781d2c6f8SDaniel Axtens  */
1380e862838SAlexander Lobakin static __always_inline bool
_test_bit(unsigned long nr,const volatile unsigned long * addr)139e69eb9c4SAlexander Lobakin _test_bit(unsigned long nr, const volatile unsigned long *addr)
14081d2c6f8SDaniel Axtens {
14127f937ccSMarco Elver 	instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long));
14281d2c6f8SDaniel Axtens 	return arch_test_bit(nr, addr);
14381d2c6f8SDaniel Axtens }
14481d2c6f8SDaniel Axtens 
145*8238b457SMikulas Patocka /**
146*8238b457SMikulas Patocka  * _test_bit_acquire - Determine, with acquire semantics, whether a bit is set
147*8238b457SMikulas Patocka  * @nr: bit number to test
148*8238b457SMikulas Patocka  * @addr: Address to start counting from
149*8238b457SMikulas Patocka  */
150*8238b457SMikulas Patocka static __always_inline bool
_test_bit_acquire(unsigned long nr,const volatile unsigned long * addr)151*8238b457SMikulas Patocka _test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
152*8238b457SMikulas Patocka {
153*8238b457SMikulas Patocka 	instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long));
154*8238b457SMikulas Patocka 	return arch_test_bit_acquire(nr, addr);
155*8238b457SMikulas Patocka }
156*8238b457SMikulas Patocka 
15781d2c6f8SDaniel Axtens #endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */
158