Commit 77514915 authored by Samuel Holland's avatar Samuel Holland Committed by Palmer Dabbelt

riscv: Enable bitops instrumentation

Instead of implementing the bitops functions directly in assembly,
provide the arch_-prefixed versions and use the wrappers from
asm-generic to add instrumentation. This improves KASAN coverage and
fixes the kasan_bitops_generic() unit test.
Signed-off-by: default avatarSamuel Holland <samuel.holland@sifive.com>
Reviewed-by: default avatarAlexandre Ghiti <alexghiti@rivosinc.com>
Tested-by: default avatarAlexandre Ghiti <alexghiti@rivosinc.com>
Link: https://lore.kernel.org/r/20240801033725.28816-3-samuel.holland@sifive.comSigned-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent 58ff5371
...@@ -222,44 +222,44 @@ static __always_inline int variable_fls(unsigned int x) ...@@ -222,44 +222,44 @@ static __always_inline int variable_fls(unsigned int x)
#define __NOT(x) (~(x)) #define __NOT(x) (~(x))
/** /**
* test_and_set_bit - Set a bit and return its old value * arch_test_and_set_bit - Set a bit and return its old value
* @nr: Bit to set * @nr: Bit to set
* @addr: Address to count from * @addr: Address to count from
* *
* This operation may be reordered on other architectures than x86. * This operation may be reordered on other architectures than x86.
*/ */
static inline int test_and_set_bit(int nr, volatile unsigned long *addr) static inline int arch_test_and_set_bit(int nr, volatile unsigned long *addr)
{ {
return __test_and_op_bit(or, __NOP, nr, addr); return __test_and_op_bit(or, __NOP, nr, addr);
} }
/** /**
* test_and_clear_bit - Clear a bit and return its old value * arch_test_and_clear_bit - Clear a bit and return its old value
* @nr: Bit to clear * @nr: Bit to clear
* @addr: Address to count from * @addr: Address to count from
* *
* This operation can be reordered on other architectures other than x86. * This operation can be reordered on other architectures other than x86.
*/ */
static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) static inline int arch_test_and_clear_bit(int nr, volatile unsigned long *addr)
{ {
return __test_and_op_bit(and, __NOT, nr, addr); return __test_and_op_bit(and, __NOT, nr, addr);
} }
/** /**
* test_and_change_bit - Change a bit and return its old value * arch_test_and_change_bit - Change a bit and return its old value
* @nr: Bit to change * @nr: Bit to change
* @addr: Address to count from * @addr: Address to count from
* *
* This operation is atomic and cannot be reordered. * This operation is atomic and cannot be reordered.
* It also implies a memory barrier. * It also implies a memory barrier.
*/ */
static inline int test_and_change_bit(int nr, volatile unsigned long *addr) static inline int arch_test_and_change_bit(int nr, volatile unsigned long *addr)
{ {
return __test_and_op_bit(xor, __NOP, nr, addr); return __test_and_op_bit(xor, __NOP, nr, addr);
} }
/** /**
* set_bit - Atomically set a bit in memory * arch_set_bit - Atomically set a bit in memory
* @nr: the bit to set * @nr: the bit to set
* @addr: the address to start counting from * @addr: the address to start counting from
* *
...@@ -270,13 +270,13 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr) ...@@ -270,13 +270,13 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
* Note that @nr may be almost arbitrarily large; this function is not * Note that @nr may be almost arbitrarily large; this function is not
* restricted to acting on a single-word quantity. * restricted to acting on a single-word quantity.
*/ */
static inline void set_bit(int nr, volatile unsigned long *addr) static inline void arch_set_bit(int nr, volatile unsigned long *addr)
{ {
__op_bit(or, __NOP, nr, addr); __op_bit(or, __NOP, nr, addr);
} }
/** /**
* clear_bit - Clears a bit in memory * arch_clear_bit - Clears a bit in memory
* @nr: Bit to clear * @nr: Bit to clear
* @addr: Address to start counting from * @addr: Address to start counting from
* *
...@@ -284,13 +284,13 @@ static inline void set_bit(int nr, volatile unsigned long *addr) ...@@ -284,13 +284,13 @@ static inline void set_bit(int nr, volatile unsigned long *addr)
* on non x86 architectures, so if you are writing portable code, * on non x86 architectures, so if you are writing portable code,
* make sure not to rely on its reordering guarantees. * make sure not to rely on its reordering guarantees.
*/ */
static inline void clear_bit(int nr, volatile unsigned long *addr) static inline void arch_clear_bit(int nr, volatile unsigned long *addr)
{ {
__op_bit(and, __NOT, nr, addr); __op_bit(and, __NOT, nr, addr);
} }
/** /**
* change_bit - Toggle a bit in memory * arch_change_bit - Toggle a bit in memory
* @nr: Bit to change * @nr: Bit to change
* @addr: Address to start counting from * @addr: Address to start counting from
* *
...@@ -298,40 +298,40 @@ static inline void clear_bit(int nr, volatile unsigned long *addr) ...@@ -298,40 +298,40 @@ static inline void clear_bit(int nr, volatile unsigned long *addr)
* Note that @nr may be almost arbitrarily large; this function is not * Note that @nr may be almost arbitrarily large; this function is not
* restricted to acting on a single-word quantity. * restricted to acting on a single-word quantity.
*/ */
static inline void change_bit(int nr, volatile unsigned long *addr) static inline void arch_change_bit(int nr, volatile unsigned long *addr)
{ {
__op_bit(xor, __NOP, nr, addr); __op_bit(xor, __NOP, nr, addr);
} }
/** /**
* test_and_set_bit_lock - Set a bit and return its old value, for lock * arch_test_and_set_bit_lock - Set a bit and return its old value, for lock
* @nr: Bit to set * @nr: Bit to set
* @addr: Address to count from * @addr: Address to count from
* *
* This operation is atomic and provides acquire barrier semantics. * This operation is atomic and provides acquire barrier semantics.
* It can be used to implement bit locks. * It can be used to implement bit locks.
*/ */
static inline int test_and_set_bit_lock( static inline int arch_test_and_set_bit_lock(
unsigned long nr, volatile unsigned long *addr) unsigned long nr, volatile unsigned long *addr)
{ {
return __test_and_op_bit_ord(or, __NOP, nr, addr, .aq); return __test_and_op_bit_ord(or, __NOP, nr, addr, .aq);
} }
/** /**
* clear_bit_unlock - Clear a bit in memory, for unlock * arch_clear_bit_unlock - Clear a bit in memory, for unlock
* @nr: the bit to set * @nr: the bit to set
* @addr: the address to start counting from * @addr: the address to start counting from
* *
* This operation is atomic and provides release barrier semantics. * This operation is atomic and provides release barrier semantics.
*/ */
static inline void clear_bit_unlock( static inline void arch_clear_bit_unlock(
unsigned long nr, volatile unsigned long *addr) unsigned long nr, volatile unsigned long *addr)
{ {
__op_bit_ord(and, __NOT, nr, addr, .rl); __op_bit_ord(and, __NOT, nr, addr, .rl);
} }
/** /**
* __clear_bit_unlock - Clear a bit in memory, for unlock * arch___clear_bit_unlock - Clear a bit in memory, for unlock
* @nr: the bit to set * @nr: the bit to set
* @addr: the address to start counting from * @addr: the address to start counting from
* *
...@@ -345,13 +345,13 @@ static inline void clear_bit_unlock( ...@@ -345,13 +345,13 @@ static inline void clear_bit_unlock(
* non-atomic property here: it's a lot more instructions and we still have to * non-atomic property here: it's a lot more instructions and we still have to
* provide release semantics anyway. * provide release semantics anyway.
*/ */
static inline void __clear_bit_unlock( static inline void arch___clear_bit_unlock(
unsigned long nr, volatile unsigned long *addr) unsigned long nr, volatile unsigned long *addr)
{ {
clear_bit_unlock(nr, addr); arch_clear_bit_unlock(nr, addr);
} }
static inline bool xor_unlock_is_negative_byte(unsigned long mask, static inline bool arch_xor_unlock_is_negative_byte(unsigned long mask,
volatile unsigned long *addr) volatile unsigned long *addr)
{ {
unsigned long res; unsigned long res;
...@@ -369,6 +369,9 @@ static inline bool xor_unlock_is_negative_byte(unsigned long mask, ...@@ -369,6 +369,9 @@ static inline bool xor_unlock_is_negative_byte(unsigned long mask,
#undef __NOT #undef __NOT
#undef __AMO #undef __AMO
#include <asm-generic/bitops/instrumented-atomic.h>
#include <asm-generic/bitops/instrumented-lock.h>
#include <asm-generic/bitops/non-atomic.h> #include <asm-generic/bitops/non-atomic.h>
#include <asm-generic/bitops/le.h> #include <asm-generic/bitops/le.h>
#include <asm-generic/bitops/ext2-atomic.h> #include <asm-generic/bitops/ext2-atomic.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment