diff options
author | Zhihao Cheng <chengzhihao1@huawei.com> | 2024-11-11 16:36:46 +0800 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2024-11-11 10:32:45 +0100 |
commit | 12b706023468c8b8fb1ed0e3fb940151339b1680 (patch) | |
tree | 0f918175ca15a9ffb6918372af168c4a8b6e0659 | |
parent | b4460065025ef82f47cf4afa36f6db3b22bda591 (diff) |
ubifs-utils: Add bit operations implementations
Add bit operations implementations, because there are some bit operations
(eg. __set_bit, test_bit) used in UBIFS linux kernel libs.
This is a preparation for replacing implementation of UBIFS utils with
linux kernel libs.
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r-- | ubifs-utils/Makemodule.am | 2 | ||||
-rw-r--r-- | ubifs-utils/common/bitops.c | 37 | ||||
-rw-r--r-- | ubifs-utils/common/bitops.h | 152 | ||||
-rw-r--r-- | ubifs-utils/common/defs.h | 36 | ||||
-rw-r--r-- | ubifs-utils/common/lpt.c | 1 |
5 files changed, 192 insertions, 36 deletions
diff --git a/ubifs-utils/Makemodule.am b/ubifs-utils/Makemodule.am index 5816257..9e07507 100644 --- a/ubifs-utils/Makemodule.am +++ b/ubifs-utils/Makemodule.am @@ -3,6 +3,8 @@ common_SOURCES = \ ubifs-utils/common/linux_types.h \ ubifs-utils/common/linux_err.h \ ubifs-utils/common/atomic.h \ + ubifs-utils/common/bitops.h \ + ubifs-utils/common/bitops.c \ ubifs-utils/common/kmem.h \ ubifs-utils/common/kmem.c \ ubifs-utils/common/defs.h \ diff --git a/ubifs-utils/common/bitops.c b/ubifs-utils/common/bitops.c new file mode 100644 index 0000000..c82f1fa --- /dev/null +++ b/ubifs-utils/common/bitops.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Realizations of bit operations. + */ + +#include "bitops.h" +#include "defs.h" + +/* + * This is a common helper function for find_next_bit and + * find_next_zero_bit. The difference is the "invert" argument, which + * is XORed with each fetched word before searching it for one bits. + */ +unsigned long _find_next_bit(const unsigned long *addr, + unsigned long nbits, unsigned long start, unsigned long invert) +{ + unsigned long tmp; + + if (!nbits || start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_LONG] ^ invert; + + /* Handle 1st word. */ + tmp &= BITMAP_FIRST_WORD_MASK(start); + start = round_down(start, BITS_PER_LONG); + + while (!tmp) { + start += BITS_PER_LONG; + if (start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_LONG] ^ invert; + } + + return min(start + __ffs(tmp), nbits); +} diff --git a/ubifs-utils/common/bitops.h b/ubifs-utils/common/bitops.h new file mode 100644 index 0000000..3a2d3f8 --- /dev/null +++ b/ubifs-utils/common/bitops.h @@ -0,0 +1,152 @@ +#ifndef __BITOPS_H__ +#define __BITOPS_H__ + +/* + * Non-atomic bitops. + */ + +#include <stdbool.h> + +#define BITS_PER_LONG __LONG_WIDTH__ +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG) + +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) + +static inline void __set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p |= mask; +} + +static inline void set_bit(int nr, volatile unsigned long *addr) +{ + __set_bit(nr, addr); +} + +static inline void __clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p &= ~mask; +} + +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + __clear_bit(nr, addr); +} + +static inline bool test_bit(int nr, const volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + return (*p & mask) != 0; +} + +/* Sets and returns original value of the bit */ +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + if (test_bit(nr, addr)) + return 1; + set_bit(nr, addr); + return 0; +} + +/** + * fls - find last (most-significant) bit set + * @x: the word to search + * + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ +static inline int fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static inline unsigned long __ffs(unsigned long word) +{ + int num = 0; + +#if BITS_PER_LONG == 64 + if ((word & 0xffffffff) == 0) { + num += 32; + word >>= 32; + } +#endif + if ((word & 0xffff) == 0) { + num += 16; + word >>= 16; + } + if ((word & 0xff) == 0) { + num += 8; + word >>= 8; + } + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +unsigned long _find_next_bit(const unsigned long *addr, + unsigned long nbits, unsigned long start, unsigned long invert); + +/* + * Find the next set bit in a memory region. + */ +static inline unsigned long find_next_bit(const unsigned long *addr, + unsigned long size, unsigned long offset) +{ + return _find_next_bit(addr, size, offset, 0UL); +} + +static inline unsigned long find_next_zero_bit(const unsigned long *addr, + unsigned long size, unsigned long offset) +{ + return _find_next_bit(addr, size, offset, ~0UL); +} + +#endif diff --git a/ubifs-utils/common/defs.h b/ubifs-utils/common/defs.h index dd3b806..485c50c 100644 --- a/ubifs-utils/common/defs.h +++ b/ubifs-utils/common/defs.h @@ -28,42 +28,6 @@ enum { MKFS_PROGRAM_TYPE = 0 }; #define unlikely(x) (x) -/** - * fls - find last (most-significant) bit set - * @x: the word to search - * - * This is defined the same way as ffs. - * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. - */ -static inline int fls(int x) -{ - int r = 32; - - if (!x) - return 0; - if (!(x & 0xffff0000u)) { - x <<= 16; - r -= 16; - } - if (!(x & 0xff000000u)) { - x <<= 8; - r -= 8; - } - if (!(x & 0xf0000000u)) { - x <<= 4; - r -= 4; - } - if (!(x & 0xc0000000u)) { - x <<= 2; - r -= 2; - } - if (!(x & 0x80000000u)) { - x <<= 1; - r -= 1; - } - return r; -} - #define do_div(n,base) ({ \ int __res; \ __res = ((unsigned long) n) % (unsigned) base; \ diff --git a/ubifs-utils/common/lpt.c b/ubifs-utils/common/lpt.c index d07f569..3c55f91 100644 --- a/ubifs-utils/common/lpt.c +++ b/ubifs-utils/common/lpt.c @@ -25,6 +25,7 @@ #endif #include "lpt.h" +#include "bitops.h" #include "defs.h" #include "ubifs.h" #include "crc16.h" |