XenevaOS
Loading...
Searching...
No Matches
bitmap.h
Go to the documentation of this file.
1#ifndef __LINUX_BITMAP_H__
2#define __LINUX_BITMAP_H__
3
4#include <linux/kernel.h>
5#include <linux/bitops.h> /* set_bit, clear_bit, test_bit, BITS_TO_LONGS,
6 * DECLARE_BITMAP. mainline's <linux/bitmap.h>
7 * includes this header too, and for the same
8 * reason: the two files are one vocabulary
9 * split by nothing but history. This one's own
10 * copies of those went away with the include
11 * -- they were duplicates, and bitops.h's
12 * take a cast that makes them work with any
13 * pointer where these did not.
14 *
15 * DECLARE_BITMAP had to move there rather than
16 * stay: this header includes bitops.h at its
17 * top, and kernel.h's chain reaches
18 * nodemask_types.h, which uses it, before
19 * returning. The full reasoning is at the top
20 * of bitops.h.
21 *
22 * bitops.h is also what xarray.c actually
23 * needs: it includes only this header but
24 * calls __set_bit/__test_and_*_bit, and a
25 * static inline it cannot see is a symbol the
26 * linker cannot find. */
27
28#define test_and_set_bit(nr, addr) \
29 ({int __old = test_bit(nr, addr); set_bit(nr, addr); __old; })
30
31#define test_and_clear_bit(nr,addr) \
32 ({ int __old = test_bit(nr, addr); clear_bit(nr,addr); __old;})
33
34#define bitmap_zero(dst, nbits) \
35 memset(dst, 0, BITS_TO_LONGS(nbits) * sizeof(unsigned long))
36
37#define bitmap_copy(dst, src, nbits) \
38 memcpy(dst, src, BITS_TO_LONGS(nbits) * sizeof(unsigned long))
39
40/*
41 * bitmap_fill / bitmap_empty / bitmap_clear -- the three the xarray port
42 * needs, added together because xarray.c:95-113 uses all three to maintain
43 * one mark word and a partial answer would be worse than none.
44 *
45 * The tail handling is not decoration. BITS_PER_LONG is 32 in this build --
46 * this target is LLP64, so `long` is four bytes -- and a request is not a
47 * multiple of it: node_any_mark() asks about XA_CHUNK_SIZE bits, which is a
48 * whole number of words, but bitmap_clear() is asked for a *range* starting
49 * at an arbitrary bit (xarray.c:136 passes xa_offset + 1), so both edges can
50 * land mid-word. Masking the last word in bitmap_empty() is what stops a
51 * set bit past the end of the requested range from making a node look
52 * marked, and it is the difference between the mark logic working and it
53 * quietly drifting.
54 *
55 * mainline's bodies live in lib/bitmap.c and reach the same three answers
56 * through native_fill()/find_next_bit(); these are the same semantics in a
57 * form that needs no second file, since the only consumer is xarray.c.
58 */
59static inline void bitmap_fill(unsigned long* dst, unsigned int nbits)
60{
61 unsigned int nlongs = BITS_TO_LONGS(nbits);
62 unsigned int tail = nbits % BITS_PER_LONG;
63
64 memset(dst, 0xff, nlongs * sizeof(unsigned long));
65 if (tail)
66 dst[nlongs - 1] &= (1UL << tail) - 1;
67}
68
69static inline int bitmap_empty(const unsigned long* src, unsigned int nbits)
70{
71 unsigned int nlongs = BITS_TO_LONGS(nbits);
72 unsigned int tail = nbits % BITS_PER_LONG;
73 unsigned int i;
74
75 for (i = 0; i < nlongs; i++)
76 {
77 unsigned long w = src[i];
78
79 if (i + 1 == nlongs && tail)
80 w &= (1UL << tail) - 1;
81 if (w)
82 return 0;
83 }
84 return 1;
85}
86
87static inline void bitmap_clear(unsigned long* map, unsigned int start, int len)
88{
89 unsigned long* p = map + (start / BITS_PER_LONG);
90 unsigned int bits = start % BITS_PER_LONG;
91
92 while (len > 0)
93 {
94 unsigned int take = BITS_PER_LONG - bits;
95 unsigned long mask;
96
97 if (take > (unsigned int)len)
98 take = (unsigned int)len;
99
100 /*
101 * The guard is the shift width, not an optimisation: when
102 * take reaches BITS_PER_LONG, `1UL << take` would shift by
103 * the width of the type, which is undefined. ~0UL is the
104 * answer that case was reaching for, and it is also the only
105 * one that covers the whole word from bit 0.
106 */
107 if (take == BITS_PER_LONG)
108 mask = ~0UL;
109 else
110 mask = ((1UL << take) - 1) << bits;
111 *p &= ~mask;
112
113 len -= take;
114 bits += take;
115 if (bits == BITS_PER_LONG)
116 {
117 p++;
118 bits = 0;
119 }
120 }
121}
122
123/*
124 * bitmap_set -- the counterpart of bitmap_clear above, same body with the
125 * mask OR-ed in instead of cleared.
126 *
127 * mainline's lives in lib/bitmap.c; this tree has no lib/bitmap.c, and the
128 * only caller is drm_edid.c's HDMI 2.0 YCbCr 4:2:0 parsing, which records a
129 * VIC by setting one bit in each of two capability maps
130 * (`bitmap_set(hdmi->y420_cmdb_modes, vic, 1)` at :6089 and the same for
131 * y420_vdb_modes at :6124). It is called with len 1 at both sites, but the
132 * range form is written out anyway: it is the same loop as bitmap_clear,
133 * so a second, single-bit implementation would be the one that could drift
134 * from the clear side when the maps are next walked in bulk.
135 *
136 * The `take == BITS_PER_LONG` branch is bitmap_clear's, for the same
137 * reason: `1UL << BITS_PER_LONG` is an undefined shift, and a full-word run
138 * is ~0UL with no shift needed. The tail of the range may also land
139 * mid-word, which is why the mask is built at `bits` rather than starting
140 * at bit 0.
141 */
142static inline void bitmap_set(unsigned long* map, unsigned int start, int len)
143{
144 unsigned long* p = map + (start / BITS_PER_LONG);
145 unsigned int bits = start % BITS_PER_LONG;
146
147 while (len > 0)
148 {
149 unsigned int take = BITS_PER_LONG - bits;
150 unsigned long mask;
151
152 if (take > (unsigned int)len)
153 take = (unsigned int)len;
154
155 if (take == BITS_PER_LONG)
156 mask = ~0UL;
157 else
158 mask = ((1UL << take) - 1) << bits;
159 *p |= mask;
160
161 len -= take;
162 bits += take;
163 if (bits == BITS_PER_LONG)
164 {
165 p++;
166 bits = 0;
167 }
168 }
169}
170
171#endif /* __LINUX_BITMAP_H__ */
#define BITS_PER_LONG
Definition bordoisila_bits.h:36
#define BITS_TO_LONGS(nr)
Definition bordoisila_bits.h:39
int map
Definition d_mode.c:31
size_t len
Definition initial.c:23
void memset(void)
int w
Definition layout.c:118
#define UL(x)
Definition const.h:78