1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */ 24ade0818SYury Norov #ifndef _TOOLS_LINUX_BITMAP_H 34ade0818SYury Norov #define _TOOLS_LINUX_BITMAP_H 4915b0882SArnaldo Carvalho de Melo 5915b0882SArnaldo Carvalho de Melo #include <string.h> 6915b0882SArnaldo Carvalho de Melo #include <linux/bitops.h> 74ade0818SYury Norov #include <linux/find.h> 898c03296SJiri Olsa #include <stdlib.h> 9c68a2aabSMatthew Wilcox #include <linux/kernel.h> 10915b0882SArnaldo Carvalho de Melo 11915b0882SArnaldo Carvalho de Melo #define DECLARE_BITMAP(name,bits) \ 12915b0882SArnaldo Carvalho de Melo unsigned long name[BITS_TO_LONGS(bits)] 13915b0882SArnaldo Carvalho de Melo 144e23eeebSLinus Torvalds unsigned int __bitmap_weight(const unsigned long *bitmap, int bits); 15915b0882SArnaldo Carvalho de Melo void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, 16915b0882SArnaldo Carvalho de Melo const unsigned long *bitmap2, int bits); 17*e2863a78SYury Norov bool __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, 18741c74f5SJiri Olsa const unsigned long *bitmap2, unsigned int bits); 19005f1700SKees Cook bool __bitmap_equal(const unsigned long *bitmap1, 208812ad41SAlexey Budankov const unsigned long *bitmap2, unsigned int bits); 2158d6ea30SMatthew Wilcox void bitmap_clear(unsigned long *map, unsigned int start, int len); 22005f1700SKees Cook bool __bitmap_intersects(const unsigned long *bitmap1, 23f20510d5SAlexey Bayduraev const unsigned long *bitmap2, unsigned int bits); 24915b0882SArnaldo Carvalho de Melo 25915b0882SArnaldo Carvalho de Melo #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) 26a719101fSYury Norov #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1))) 27915b0882SArnaldo Carvalho de Melo 28e5b9252dSYury Norov static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) 29915b0882SArnaldo Carvalho de Melo { 30915b0882SArnaldo Carvalho de Melo if (small_const_nbits(nbits)) 31915b0882SArnaldo Carvalho de Melo *dst = 0UL; 32915b0882SArnaldo Carvalho de Melo else { 33915b0882SArnaldo Carvalho de Melo int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); 34915b0882SArnaldo Carvalho de Melo memset(dst, 0, len); 35915b0882SArnaldo Carvalho de Melo } 36915b0882SArnaldo Carvalho de Melo } 37915b0882SArnaldo Carvalho de Melo 38b328daf3SMatthew Wilcox static inline void bitmap_fill(unsigned long *dst, unsigned int nbits) 39b328daf3SMatthew Wilcox { 40b328daf3SMatthew Wilcox unsigned int nlongs = BITS_TO_LONGS(nbits); 41b328daf3SMatthew Wilcox if (!small_const_nbits(nbits)) { 42b328daf3SMatthew Wilcox unsigned int len = (nlongs - 1) * sizeof(unsigned long); 43b328daf3SMatthew Wilcox memset(dst, 0xff, len); 44b328daf3SMatthew Wilcox } 45b328daf3SMatthew Wilcox dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); 46b328daf3SMatthew Wilcox } 47b328daf3SMatthew Wilcox 48*e2863a78SYury Norov static inline bool bitmap_empty(const unsigned long *src, unsigned int nbits) 49b328daf3SMatthew Wilcox { 50b328daf3SMatthew Wilcox if (small_const_nbits(nbits)) 51b328daf3SMatthew Wilcox return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); 52b328daf3SMatthew Wilcox 53b328daf3SMatthew Wilcox return find_first_bit(src, nbits) == nbits; 54b328daf3SMatthew Wilcox } 55b328daf3SMatthew Wilcox 56*e2863a78SYury Norov static inline bool bitmap_full(const unsigned long *src, unsigned int nbits) 57b328daf3SMatthew Wilcox { 58b328daf3SMatthew Wilcox if (small_const_nbits(nbits)) 59b328daf3SMatthew Wilcox return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); 60b328daf3SMatthew Wilcox 61b328daf3SMatthew Wilcox return find_first_zero_bit(src, nbits) == nbits; 62b328daf3SMatthew Wilcox } 63b328daf3SMatthew Wilcox 644e23eeebSLinus Torvalds static inline unsigned int bitmap_weight(const unsigned long *src, unsigned int nbits) 65915b0882SArnaldo Carvalho de Melo { 66915b0882SArnaldo Carvalho de Melo if (small_const_nbits(nbits)) 67915b0882SArnaldo Carvalho de Melo return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits)); 68915b0882SArnaldo Carvalho de Melo return __bitmap_weight(src, nbits); 69915b0882SArnaldo Carvalho de Melo } 70915b0882SArnaldo Carvalho de Melo 71915b0882SArnaldo Carvalho de Melo static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, 72e5b9252dSYury Norov const unsigned long *src2, unsigned int nbits) 73915b0882SArnaldo Carvalho de Melo { 74915b0882SArnaldo Carvalho de Melo if (small_const_nbits(nbits)) 75915b0882SArnaldo Carvalho de Melo *dst = *src1 | *src2; 76915b0882SArnaldo Carvalho de Melo else 77915b0882SArnaldo Carvalho de Melo __bitmap_or(dst, src1, src2, nbits); 78915b0882SArnaldo Carvalho de Melo } 79915b0882SArnaldo Carvalho de Melo 80915b0882SArnaldo Carvalho de Melo /** 81915b0882SArnaldo Carvalho de Melo * test_and_set_bit - Set a bit and return its old value 82915b0882SArnaldo Carvalho de Melo * @nr: Bit to set 83915b0882SArnaldo Carvalho de Melo * @addr: Address to count from 84915b0882SArnaldo Carvalho de Melo */ 85915b0882SArnaldo Carvalho de Melo static inline int test_and_set_bit(int nr, unsigned long *addr) 86915b0882SArnaldo Carvalho de Melo { 87915b0882SArnaldo Carvalho de Melo unsigned long mask = BIT_MASK(nr); 88915b0882SArnaldo Carvalho de Melo unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 89915b0882SArnaldo Carvalho de Melo unsigned long old; 90915b0882SArnaldo Carvalho de Melo 91915b0882SArnaldo Carvalho de Melo old = *p; 92915b0882SArnaldo Carvalho de Melo *p = old | mask; 93915b0882SArnaldo Carvalho de Melo 94915b0882SArnaldo Carvalho de Melo return (old & mask) != 0; 95915b0882SArnaldo Carvalho de Melo } 96915b0882SArnaldo Carvalho de Melo 9798c03296SJiri Olsa /** 9807a262ccSPeter Xu * test_and_clear_bit - Clear a bit and return its old value 9907a262ccSPeter Xu * @nr: Bit to clear 10007a262ccSPeter Xu * @addr: Address to count from 10107a262ccSPeter Xu */ 10207a262ccSPeter Xu static inline int test_and_clear_bit(int nr, unsigned long *addr) 10307a262ccSPeter Xu { 10407a262ccSPeter Xu unsigned long mask = BIT_MASK(nr); 10507a262ccSPeter Xu unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); 10607a262ccSPeter Xu unsigned long old; 10707a262ccSPeter Xu 10807a262ccSPeter Xu old = *p; 10907a262ccSPeter Xu *p = old & ~mask; 11007a262ccSPeter Xu 11107a262ccSPeter Xu return (old & mask) != 0; 11207a262ccSPeter Xu } 11307a262ccSPeter Xu 11407a262ccSPeter Xu /** 1157fc5b571SAndy Shevchenko * bitmap_zalloc - Allocate bitmap 116e2091cedSJiri Olsa * @nbits: Number of bits 11798c03296SJiri Olsa */ 1187fc5b571SAndy Shevchenko static inline unsigned long *bitmap_zalloc(int nbits) 11998c03296SJiri Olsa { 12098c03296SJiri Olsa return calloc(1, BITS_TO_LONGS(nbits) * sizeof(unsigned long)); 12198c03296SJiri Olsa } 12298c03296SJiri Olsa 123820d12b7SJiri Olsa /* 1248812ad41SAlexey Budankov * bitmap_free - Free bitmap 1258812ad41SAlexey Budankov * @bitmap: pointer to bitmap 1268812ad41SAlexey Budankov */ 1278812ad41SAlexey Budankov static inline void bitmap_free(unsigned long *bitmap) 1288812ad41SAlexey Budankov { 1298812ad41SAlexey Budankov free(bitmap); 1308812ad41SAlexey Budankov } 1318812ad41SAlexey Budankov 1328812ad41SAlexey Budankov /* 133820d12b7SJiri Olsa * bitmap_scnprintf - print bitmap list into buffer 134820d12b7SJiri Olsa * @bitmap: bitmap 135820d12b7SJiri Olsa * @nbits: size of bitmap 136820d12b7SJiri Olsa * @buf: buffer to store output 137820d12b7SJiri Olsa * @size: size of @buf 138820d12b7SJiri Olsa */ 139e5b9252dSYury Norov size_t bitmap_scnprintf(unsigned long *bitmap, unsigned int nbits, 140820d12b7SJiri Olsa char *buf, size_t size); 141820d12b7SJiri Olsa 142741c74f5SJiri Olsa /** 143741c74f5SJiri Olsa * bitmap_and - Do logical and on bitmaps 144741c74f5SJiri Olsa * @dst: resulting bitmap 145741c74f5SJiri Olsa * @src1: operand 1 146741c74f5SJiri Olsa * @src2: operand 2 147741c74f5SJiri Olsa * @nbits: size of bitmap 148741c74f5SJiri Olsa */ 149*e2863a78SYury Norov static inline bool bitmap_and(unsigned long *dst, const unsigned long *src1, 150741c74f5SJiri Olsa const unsigned long *src2, unsigned int nbits) 151741c74f5SJiri Olsa { 152741c74f5SJiri Olsa if (small_const_nbits(nbits)) 153741c74f5SJiri Olsa return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0; 154741c74f5SJiri Olsa return __bitmap_and(dst, src1, src2, nbits); 155741c74f5SJiri Olsa } 156741c74f5SJiri Olsa 1578812ad41SAlexey Budankov #ifdef __LITTLE_ENDIAN 1588812ad41SAlexey Budankov #define BITMAP_MEM_ALIGNMENT 8 1598812ad41SAlexey Budankov #else 1608812ad41SAlexey Budankov #define BITMAP_MEM_ALIGNMENT (8 * sizeof(unsigned long)) 1618812ad41SAlexey Budankov #endif 1628812ad41SAlexey Budankov #define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1) 1638812ad41SAlexey Budankov #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) 1648812ad41SAlexey Budankov 165005f1700SKees Cook static inline bool bitmap_equal(const unsigned long *src1, 1668812ad41SAlexey Budankov const unsigned long *src2, unsigned int nbits) 1678812ad41SAlexey Budankov { 1688812ad41SAlexey Budankov if (small_const_nbits(nbits)) 1698812ad41SAlexey Budankov return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); 1708812ad41SAlexey Budankov if (__builtin_constant_p(nbits & BITMAP_MEM_MASK) && 1718812ad41SAlexey Budankov IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) 1728812ad41SAlexey Budankov return !memcmp(src1, src2, nbits / 8); 1738812ad41SAlexey Budankov return __bitmap_equal(src1, src2, nbits); 1748812ad41SAlexey Budankov } 1758812ad41SAlexey Budankov 176005f1700SKees Cook static inline bool bitmap_intersects(const unsigned long *src1, 177005f1700SKees Cook const unsigned long *src2, 178005f1700SKees Cook unsigned int nbits) 179f20510d5SAlexey Bayduraev { 180f20510d5SAlexey Bayduraev if (small_const_nbits(nbits)) 181f20510d5SAlexey Bayduraev return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; 182f20510d5SAlexey Bayduraev else 183f20510d5SAlexey Bayduraev return __bitmap_intersects(src1, src2, nbits); 184f20510d5SAlexey Bayduraev } 185f20510d5SAlexey Bayduraev 1864ade0818SYury Norov #endif /* _TOOLS_LINUX_BITMAP_H */ 187