18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci/*
48c2ecf20Sopenharmony_ci * This file provides wrappers with sanitizer instrumentation for non-atomic
58c2ecf20Sopenharmony_ci * bit operations.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * To use this functionality, an arch's bitops.h file needs to define each of
88c2ecf20Sopenharmony_ci * the below bit operations with an arch_ prefix (e.g. arch_set_bit(),
98c2ecf20Sopenharmony_ci * arch___set_bit(), etc.).
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#ifndef _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H
128c2ecf20Sopenharmony_ci#define _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/instrumented.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/**
178c2ecf20Sopenharmony_ci * __set_bit - Set a bit in memory
188c2ecf20Sopenharmony_ci * @nr: the bit to set
198c2ecf20Sopenharmony_ci * @addr: the address to start counting from
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * Unlike set_bit(), this function is non-atomic. If it is called on the same
228c2ecf20Sopenharmony_ci * region of memory concurrently, the effect may be that only one operation
238c2ecf20Sopenharmony_ci * succeeds.
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_cistatic inline void __set_bit(long nr, volatile unsigned long *addr)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	instrument_write(addr + BIT_WORD(nr), sizeof(long));
288c2ecf20Sopenharmony_ci	arch___set_bit(nr, addr);
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/**
328c2ecf20Sopenharmony_ci * __clear_bit - Clears a bit in memory
338c2ecf20Sopenharmony_ci * @nr: the bit to clear
348c2ecf20Sopenharmony_ci * @addr: the address to start counting from
358c2ecf20Sopenharmony_ci *
368c2ecf20Sopenharmony_ci * Unlike clear_bit(), this function is non-atomic. If it is called on the same
378c2ecf20Sopenharmony_ci * region of memory concurrently, the effect may be that only one operation
388c2ecf20Sopenharmony_ci * succeeds.
398c2ecf20Sopenharmony_ci */
408c2ecf20Sopenharmony_cistatic inline void __clear_bit(long nr, volatile unsigned long *addr)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	instrument_write(addr + BIT_WORD(nr), sizeof(long));
438c2ecf20Sopenharmony_ci	arch___clear_bit(nr, addr);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/**
478c2ecf20Sopenharmony_ci * __change_bit - Toggle a bit in memory
488c2ecf20Sopenharmony_ci * @nr: the bit to change
498c2ecf20Sopenharmony_ci * @addr: the address to start counting from
508c2ecf20Sopenharmony_ci *
518c2ecf20Sopenharmony_ci * Unlike change_bit(), this function is non-atomic. If it is called on the same
528c2ecf20Sopenharmony_ci * region of memory concurrently, the effect may be that only one operation
538c2ecf20Sopenharmony_ci * succeeds.
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_cistatic inline void __change_bit(long nr, volatile unsigned long *addr)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	instrument_write(addr + BIT_WORD(nr), sizeof(long));
588c2ecf20Sopenharmony_ci	arch___change_bit(nr, addr);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic inline void __instrument_read_write_bitop(long nr, volatile unsigned long *addr)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	if (IS_ENABLED(CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC)) {
648c2ecf20Sopenharmony_ci		/*
658c2ecf20Sopenharmony_ci		 * We treat non-atomic read-write bitops a little more special.
668c2ecf20Sopenharmony_ci		 * Given the operations here only modify a single bit, assuming
678c2ecf20Sopenharmony_ci		 * non-atomicity of the writer is sufficient may be reasonable
688c2ecf20Sopenharmony_ci		 * for certain usage (and follows the permissible nature of the
698c2ecf20Sopenharmony_ci		 * assume-plain-writes-atomic rule):
708c2ecf20Sopenharmony_ci		 * 1. report read-modify-write races -> check read;
718c2ecf20Sopenharmony_ci		 * 2. do not report races with marked readers, but do report
728c2ecf20Sopenharmony_ci		 *    races with unmarked readers -> check "atomic" write.
738c2ecf20Sopenharmony_ci		 */
748c2ecf20Sopenharmony_ci		kcsan_check_read(addr + BIT_WORD(nr), sizeof(long));
758c2ecf20Sopenharmony_ci		/*
768c2ecf20Sopenharmony_ci		 * Use generic write instrumentation, in case other sanitizers
778c2ecf20Sopenharmony_ci		 * or tools are enabled alongside KCSAN.
788c2ecf20Sopenharmony_ci		 */
798c2ecf20Sopenharmony_ci		instrument_write(addr + BIT_WORD(nr), sizeof(long));
808c2ecf20Sopenharmony_ci	} else {
818c2ecf20Sopenharmony_ci		instrument_read_write(addr + BIT_WORD(nr), sizeof(long));
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/**
868c2ecf20Sopenharmony_ci * __test_and_set_bit - Set a bit and return its old value
878c2ecf20Sopenharmony_ci * @nr: Bit to set
888c2ecf20Sopenharmony_ci * @addr: Address to count from
898c2ecf20Sopenharmony_ci *
908c2ecf20Sopenharmony_ci * This operation is non-atomic. If two instances of this operation race, one
918c2ecf20Sopenharmony_ci * can appear to succeed but actually fail.
928c2ecf20Sopenharmony_ci */
938c2ecf20Sopenharmony_cistatic inline bool __test_and_set_bit(long nr, volatile unsigned long *addr)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	__instrument_read_write_bitop(nr, addr);
968c2ecf20Sopenharmony_ci	return arch___test_and_set_bit(nr, addr);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/**
1008c2ecf20Sopenharmony_ci * __test_and_clear_bit - Clear a bit and return its old value
1018c2ecf20Sopenharmony_ci * @nr: Bit to clear
1028c2ecf20Sopenharmony_ci * @addr: Address to count from
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * This operation is non-atomic. If two instances of this operation race, one
1058c2ecf20Sopenharmony_ci * can appear to succeed but actually fail.
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_cistatic inline bool __test_and_clear_bit(long nr, volatile unsigned long *addr)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	__instrument_read_write_bitop(nr, addr);
1108c2ecf20Sopenharmony_ci	return arch___test_and_clear_bit(nr, addr);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/**
1148c2ecf20Sopenharmony_ci * __test_and_change_bit - Change a bit and return its old value
1158c2ecf20Sopenharmony_ci * @nr: Bit to change
1168c2ecf20Sopenharmony_ci * @addr: Address to count from
1178c2ecf20Sopenharmony_ci *
1188c2ecf20Sopenharmony_ci * This operation is non-atomic. If two instances of this operation race, one
1198c2ecf20Sopenharmony_ci * can appear to succeed but actually fail.
1208c2ecf20Sopenharmony_ci */
1218c2ecf20Sopenharmony_cistatic inline bool __test_and_change_bit(long nr, volatile unsigned long *addr)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	__instrument_read_write_bitop(nr, addr);
1248c2ecf20Sopenharmony_ci	return arch___test_and_change_bit(nr, addr);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/**
1288c2ecf20Sopenharmony_ci * test_bit - Determine whether a bit is set
1298c2ecf20Sopenharmony_ci * @nr: bit number to test
1308c2ecf20Sopenharmony_ci * @addr: Address to start counting from
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_cistatic inline bool test_bit(long nr, const volatile unsigned long *addr)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long));
1358c2ecf20Sopenharmony_ci	return arch_test_bit(nr, addr);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci#endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */
139