162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci * This file provides wrappers with sanitizer instrumentation for non-atomic
562306a36Sopenharmony_ci * bit operations.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * To use this functionality, an arch's bitops.h file needs to define each of
862306a36Sopenharmony_ci * the below bit operations with an arch_ prefix (e.g. arch_set_bit(),
962306a36Sopenharmony_ci * arch___set_bit(), etc.).
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#ifndef _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H
1262306a36Sopenharmony_ci#define _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/instrumented.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/**
1762306a36Sopenharmony_ci * ___set_bit - Set a bit in memory
1862306a36Sopenharmony_ci * @nr: the bit to set
1962306a36Sopenharmony_ci * @addr: the address to start counting from
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Unlike set_bit(), this function is non-atomic. If it is called on the same
2262306a36Sopenharmony_ci * region of memory concurrently, the effect may be that only one operation
2362306a36Sopenharmony_ci * succeeds.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_cistatic __always_inline void
2662306a36Sopenharmony_ci___set_bit(unsigned long nr, volatile unsigned long *addr)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	instrument_write(addr + BIT_WORD(nr), sizeof(long));
2962306a36Sopenharmony_ci	arch___set_bit(nr, addr);
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/**
3362306a36Sopenharmony_ci * ___clear_bit - Clears a bit in memory
3462306a36Sopenharmony_ci * @nr: the bit to clear
3562306a36Sopenharmony_ci * @addr: the address to start counting from
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * Unlike clear_bit(), this function is non-atomic. If it is called on the same
3862306a36Sopenharmony_ci * region of memory concurrently, the effect may be that only one operation
3962306a36Sopenharmony_ci * succeeds.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_cistatic __always_inline void
4262306a36Sopenharmony_ci___clear_bit(unsigned long nr, volatile unsigned long *addr)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	instrument_write(addr + BIT_WORD(nr), sizeof(long));
4562306a36Sopenharmony_ci	arch___clear_bit(nr, addr);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/**
4962306a36Sopenharmony_ci * ___change_bit - Toggle a bit in memory
5062306a36Sopenharmony_ci * @nr: the bit to change
5162306a36Sopenharmony_ci * @addr: the address to start counting from
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci * Unlike change_bit(), this function is non-atomic. If it is called on the same
5462306a36Sopenharmony_ci * region of memory concurrently, the effect may be that only one operation
5562306a36Sopenharmony_ci * succeeds.
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_cistatic __always_inline void
5862306a36Sopenharmony_ci___change_bit(unsigned long nr, volatile unsigned long *addr)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	instrument_write(addr + BIT_WORD(nr), sizeof(long));
6162306a36Sopenharmony_ci	arch___change_bit(nr, addr);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic __always_inline void __instrument_read_write_bitop(long nr, volatile unsigned long *addr)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC)) {
6762306a36Sopenharmony_ci		/*
6862306a36Sopenharmony_ci		 * We treat non-atomic read-write bitops a little more special.
6962306a36Sopenharmony_ci		 * Given the operations here only modify a single bit, assuming
7062306a36Sopenharmony_ci		 * non-atomicity of the writer is sufficient may be reasonable
7162306a36Sopenharmony_ci		 * for certain usage (and follows the permissible nature of the
7262306a36Sopenharmony_ci		 * assume-plain-writes-atomic rule):
7362306a36Sopenharmony_ci		 * 1. report read-modify-write races -> check read;
7462306a36Sopenharmony_ci		 * 2. do not report races with marked readers, but do report
7562306a36Sopenharmony_ci		 *    races with unmarked readers -> check "atomic" write.
7662306a36Sopenharmony_ci		 */
7762306a36Sopenharmony_ci		kcsan_check_read(addr + BIT_WORD(nr), sizeof(long));
7862306a36Sopenharmony_ci		/*
7962306a36Sopenharmony_ci		 * Use generic write instrumentation, in case other sanitizers
8062306a36Sopenharmony_ci		 * or tools are enabled alongside KCSAN.
8162306a36Sopenharmony_ci		 */
8262306a36Sopenharmony_ci		instrument_write(addr + BIT_WORD(nr), sizeof(long));
8362306a36Sopenharmony_ci	} else {
8462306a36Sopenharmony_ci		instrument_read_write(addr + BIT_WORD(nr), sizeof(long));
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/**
8962306a36Sopenharmony_ci * ___test_and_set_bit - Set a bit and return its old value
9062306a36Sopenharmony_ci * @nr: Bit to set
9162306a36Sopenharmony_ci * @addr: Address to count from
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * This operation is non-atomic. If two instances of this operation race, one
9462306a36Sopenharmony_ci * can appear to succeed but actually fail.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_cistatic __always_inline bool
9762306a36Sopenharmony_ci___test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	__instrument_read_write_bitop(nr, addr);
10062306a36Sopenharmony_ci	return arch___test_and_set_bit(nr, addr);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/**
10462306a36Sopenharmony_ci * ___test_and_clear_bit - Clear a bit and return its old value
10562306a36Sopenharmony_ci * @nr: Bit to clear
10662306a36Sopenharmony_ci * @addr: Address to count from
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * This operation is non-atomic. If two instances of this operation race, one
10962306a36Sopenharmony_ci * can appear to succeed but actually fail.
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_cistatic __always_inline bool
11262306a36Sopenharmony_ci___test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	__instrument_read_write_bitop(nr, addr);
11562306a36Sopenharmony_ci	return arch___test_and_clear_bit(nr, addr);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/**
11962306a36Sopenharmony_ci * ___test_and_change_bit - Change a bit and return its old value
12062306a36Sopenharmony_ci * @nr: Bit to change
12162306a36Sopenharmony_ci * @addr: Address to count from
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * This operation is non-atomic. If two instances of this operation race, one
12462306a36Sopenharmony_ci * can appear to succeed but actually fail.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_cistatic __always_inline bool
12762306a36Sopenharmony_ci___test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	__instrument_read_write_bitop(nr, addr);
13062306a36Sopenharmony_ci	return arch___test_and_change_bit(nr, addr);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/**
13462306a36Sopenharmony_ci * _test_bit - Determine whether a bit is set
13562306a36Sopenharmony_ci * @nr: bit number to test
13662306a36Sopenharmony_ci * @addr: Address to start counting from
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_cistatic __always_inline bool
13962306a36Sopenharmony_ci_test_bit(unsigned long nr, const volatile unsigned long *addr)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long));
14262306a36Sopenharmony_ci	return arch_test_bit(nr, addr);
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/**
14662306a36Sopenharmony_ci * _test_bit_acquire - Determine, with acquire semantics, whether a bit is set
14762306a36Sopenharmony_ci * @nr: bit number to test
14862306a36Sopenharmony_ci * @addr: Address to start counting from
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistatic __always_inline bool
15162306a36Sopenharmony_ci_test_bit_acquire(unsigned long nr, const volatile unsigned long *addr)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	instrument_atomic_read(addr + BIT_WORD(nr), sizeof(long));
15462306a36Sopenharmony_ci	return arch_test_bit_acquire(nr, addr);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci#endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */
158