PatchworkOS  19e446b
A non-POSIX operating system.
Loading...
Searching...
No Matches
bitmap.h
Go to the documentation of this file.
1#ifndef _SYS_BITMAP_H
2#define _SYS_BITMAP_H 1
3
4#include <errno.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <sys/math.h>
8
9/**
10 * @brief A bitmap optimized using 64-bit words.
11 * @defgroup libstd_sys_bitmap Bitmap
12 * @ingroup libstd
13 *
14 * @{
15 */
16
17/**
18 * @brief Bitmap structure.
19 * @struct bitmap_t
20 */
27
28/**
29 * @brief Convert number of bits to number of qwords.
30 *
31 * @param bits Number of bits.
32 * @return Number of qwords.
33 */
34#define BITMAP_BITS_TO_QWORDS(bits) (((bits) + 63) / 64)
35
36/**
37 * @brief Convert number of bits to number of bytes.
38 *
39 * @param bits Number of bits.
40 * @return Number of bytes.
41 */
42#define BITMAP_BITS_TO_BYTES(bits) (BITMAP_BITS_TO_QWORDS(bits) * sizeof(uint64_t))
43
44/**
45 * @brief Convert number of qwords to number of bits.
46 *
47 * @param qwords Number of qwords.
48 * @return Number of bits.
49 */
50#define BITMAP_QWORDS_TO_BITS(qwords) ((qwords) * 64)
51
52/**
53 * @brief Iterate over each set bit in the bitmap.
54 *
55 * @param idx Pointer to store the current index.
56 * @param map The bitmap.
57 */
58#define BITMAP_FOR_EACH_SET(idx, map) \
59 for (uint64_t qwordIdx = 0; qwordIdx < BITMAP_BITS_TO_QWORDS((map)->length); qwordIdx++) \
60 for (uint64_t tempQword = (map)->buffer[qwordIdx]; tempQword != 0; tempQword &= (tempQword - 1)) \
61 if (({ \
62 uint64_t bit = __builtin_ctzll(tempQword); \
63 *(idx) = qwordIdx * 64 + bit; \
64 *(idx) < (map)->length; \
65 }))
66
67/**
68 * @brief Define and create a bitmap and its buffer.
69 *
70 * @param name Name of the bitmap.
71 * @param bits Length of the bitmap in bits.
72 */
73#define BITMAP_CREATE(name, bits) \
74 uint64_t name##Buffer[BITMAP_BITS_TO_QWORDS(bits)]; \
75 bitmap_t name = {.firstZeroIdx = 0, .length = (bits), .buffer = name##Buffer}
76
77/**
78 * @brief Define and create a zero-initialized bitmap and its buffer.
79 *
80 * @param name Name of the bitmap.
81 * @param bits Length of the bitmap in bits.
82 */
83#define BITMAP_CREATE_ZERO(name, bits) \
84 uint64_t name##Buffer[BITMAP_BITS_TO_QWORDS(bits)] = {0}; \
85 bitmap_t name = {.firstZeroIdx = 0, .length = (bits), .buffer = name##Buffer}
86
87/**
88 * @brief Define and create a one-initialized bitmap and its buffer.
89 *
90 * @param name Name of the bitmap.
91 * @param bits Length of the bitmap in bits.
92 */
93#define BITMAP_CREATE_ONE(name, bits) \
94 uint64_t name##Buffer[BITMAP_BITS_TO_QWORDS(bits)] = {-1ULL}; \
95 bitmap_t name = {.firstZeroIdx = 0, .length = (bits), .buffer = name##Buffer}
96
97/**
98 * @brief Define a bitmap and its buffer.
99 *
100 * Will not initialize the bitmap, use `BITMAP_DEFINE_INIT` to initialize it.
101 *
102 * Intended to be used for struct members.
103 *
104 * @param name Name of the bitmap.
105 * @param bits Length of the bitmap in bits.
106 */
107#define BITMAP_DEFINE(name, bits) \
108 uint64_t name##Buffer[BITMAP_BITS_TO_QWORDS(bits)]; \
109 bitmap_t name
110
111/**
112 * @brief Initialize a bitmap defined with `BITMAP_DEFINE`.
113 *
114 * @param name Name of the bitmap.
115 * @param bits Length of the bitmap in bits.
116 */
117#define BITMAP_DEFINE_INIT(name, bits) \
118 bitmap_init(&(name), name##Buffer, bits); \
119 memset(name##Buffer, 0, BITMAP_BITS_TO_BYTES(bits))
120
121/**
122 * @brief Initialize a bitmap.
123 *
124 * @param map The bitmap.
125 * @param buffer Pointer to the buffer, must be a multiple of 8 bytes.
126 * @param length Length of the bitmap in bits.
127 */
128static inline void bitmap_init(bitmap_t* map, void* buffer, uint64_t length)
129{
130 map->firstZeroIdx = 0;
131 map->length = length;
132 map->buffer = (uint64_t*)buffer;
133}
134
135/**
136 * @brief Check if the bitmap is empty (all bits clear).
137 *
138 * @param map The bitmap.
139 * @return true if the bitmap is empty, false otherwise.
140 */
141static inline bool bitmap_is_empty(bitmap_t* map)
142{
143 uint64_t fullQwords = map->length / 64;
144 for (uint64_t i = 0; i < fullQwords; i++)
145 {
146 if (map->buffer[i] != 0)
147 {
148 return false;
149 }
150 }
151
152 uint64_t remainingBits = map->length % 64;
153 if (remainingBits != 0)
154 {
155 uint64_t mask = (1ULL << remainingBits) - 1;
156 if ((map->buffer[fullQwords] & mask) != 0)
157 {
158 return false;
159 }
160 }
161
162 return true;
163}
164
165/**
166 * @brief Check if a bit is set in the bitmap.
167 *
168 * @param map The bitmap.
169 * @param idx Index of the bit to check.
170 * @return true if the bit is set, false otherwise.
171 */
172static inline bool bitmap_is_set(bitmap_t* map, uint64_t idx)
173{
174 if (idx >= map->length)
175 {
176 return false;
177 }
178
179 uint64_t qwordIdx = idx / 64;
180 uint64_t bitInQword = idx % 64;
181 return (map->buffer[qwordIdx] & (1ULL << bitInQword));
182}
183
184/**
185 * @brief Set a bit in the bitmap.
186 *
187 * @param map Pointer to the bitmap.
188 * @param index Index of the bit to set.
189 */
190static inline void bitmap_set(bitmap_t* map, uint64_t index)
191{
192 if (index >= map->length)
193 {
194 return;
195 }
196
197 uint64_t qwordIdx = index / 64;
198 uint64_t bitInQword = index % 64;
199 map->buffer[qwordIdx] |= (1ULL << bitInQword);
200}
201
202/**
203 * @brief Set a range of bits in the bitmap.
204 *
205 * @param map Pointer to the bitmap.
206 * @param low Low index of the range (inclusive).
207 * @param high High index of the range (exclusive).
208 */
209static inline void bitmap_set_range(bitmap_t* map, uint64_t low, uint64_t high)
210{
211 if (low >= high || high > map->length)
212 {
213 return;
214 }
215
216 uint64_t firstQwordIdx = low / 64;
217 uint64_t firstBitInQword = low % 64;
218 uint64_t lastQwordIdx = (high - 1) / 64;
219 uint64_t lastBitInQword = (high - 1) % 64;
220
221 if (firstQwordIdx == lastQwordIdx)
222 {
223 uint64_t mask = (~0ULL << firstBitInQword) & (~0ULL >> (63 - lastBitInQword));
224 map->buffer[firstQwordIdx] |= mask;
225 return;
226 }
227
228 map->buffer[firstQwordIdx] |= (~0ULL << firstBitInQword);
229
230 for (uint64_t i = firstQwordIdx + 1; i < lastQwordIdx; i++)
231 {
232 map->buffer[i] = ~0ULL;
233 }
234
235 map->buffer[lastQwordIdx] |= (~0ULL >> (63 - lastBitInQword));
236}
237
238/**
239 * @brief Clear a bit in the bitmap.
240 *
241 * @param map Pointer to the bitmap.
242 * @param index Index of the bit to clear.
243 */
244static inline void bitmap_clear(bitmap_t* map, uint64_t index)
245{
246 if (index >= map->length)
247 {
248 return;
249 }
250
251 uint64_t qwordIdx = index / 64;
252 uint64_t bitInQword = index % 64;
253 map->buffer[qwordIdx] &= ~(1ULL << bitInQword);
254 map->firstZeroIdx = MIN(map->firstZeroIdx, index);
255}
256
257/**
258 * @brief Clear a range of bits in the bitmap.
259 *
260 * @param map Pointer to the bitmap.
261 * @param low Low index of the range (inclusive).
262 * @param high High index of the range (exclusive).
263 */
264static inline void bitmap_clear_range(bitmap_t* map, uint64_t low, uint64_t high)
265{
266 if (low >= high || high > map->length)
267 {
268 return;
269 }
270
271 if (low < map->firstZeroIdx)
272 {
273 map->firstZeroIdx = low;
274 }
275
276 uint64_t firstQwordIdx = low / 64;
277 uint64_t firstBitInQword = low % 64;
278 uint64_t lastQwordIdx = (high - 1) / 64;
279 uint64_t lastBitInQword = (high - 1) % 64;
280
281 if (firstQwordIdx == lastQwordIdx)
282 {
283 uint64_t mask = (~0ULL << firstBitInQword) & (~0ULL >> (63 - lastBitInQword));
284 map->buffer[firstQwordIdx] &= ~mask;
285 return;
286 }
287
288 map->buffer[firstQwordIdx] &= ~(~0ULL << firstBitInQword);
289
290 for (uint64_t i = firstQwordIdx + 1; i < lastQwordIdx; i++)
291 {
292 map->buffer[i] = 0ULL;
293 }
294
295 map->buffer[lastQwordIdx] &= ~(~0ULL >> (63 - lastBitInQword));
296}
297
298/**
299 * @brief Find the first clear bit in the bitmap.
300 *
301 * @param map The bitmap.
302 * @param startIdx Index to start searching from.
303 * @param endIdx Index to stop searching at (exclusive).
304 * @return Index of the first clear bit, or `map->length` if none found.
305 */
307{
308 if (map->firstZeroIdx >= map->length)
309 {
310 return map->length;
311 }
312
313 startIdx = MAX(startIdx, map->firstZeroIdx);
314 uint64_t qwordIdx = startIdx / 64;
315 uint64_t bitIdx = startIdx % 64;
316 uint64_t endQwordIdx = BITMAP_BITS_TO_QWORDS(MIN(endIdx, map->length));
317
318 if (bitIdx != 0)
319 {
320 uint64_t qword = map->buffer[qwordIdx];
321 uint64_t maskedQword = qword | ((1ULL << bitIdx) - 1);
322 if (maskedQword != ~0ULL)
323 {
324 uint64_t res = qwordIdx * 64 + __builtin_ctzll(~maskedQword);
325 return res < endIdx ? res : map->length;
326 }
327 qwordIdx++;
328 }
329
330 for (uint64_t i = qwordIdx; i < endQwordIdx; ++i)
331 {
332 if (map->buffer[i] != ~0ULL)
333 {
334 uint64_t res = i * 64 + __builtin_ctzll(~map->buffer[i]);
335 return res < endIdx ? res : map->length;
336 }
337 }
338
339 return map->length;
340}
341
342/**
343 * @brief Find the first set bit in the bitmap.
344 *
345 * @param map The bitmap.
346 * @param startIdx Index to start searching from.
347 * @param endIdx Index to stop searching at (exclusive).
348 * @return Index of the first set bit, or `map->length` if none found.
349 */
351{
352 if (startIdx >= map->length)
353 {
354 return map->length;
355 }
356
357 uint64_t startQwordIdx = startIdx / 64;
358 uint64_t startBitIdx = startIdx % 64;
359 uint64_t endQwordIdx = BITMAP_BITS_TO_QWORDS(MIN(endIdx, map->length));
360
361 while (startQwordIdx < endQwordIdx)
362 {
363 uint64_t qword = map->buffer[startQwordIdx];
364 if (startBitIdx != 0)
365 {
366 qword &= ~((1ULL << startBitIdx) - 1);
367 }
368
369 if (qword != 0)
370 {
371 uint64_t res = startQwordIdx * 64 + __builtin_ctzll(qword);
372 return res < endIdx ? res : map->length;
373 }
374
375 startQwordIdx++;
376 startBitIdx = 0;
377 }
378
379 return map->length;
380}
381
382/**
383 * @brief Find a clear region of specified length and alignment, and set it.
384 *
385 * @param map Pointer to the bitmap.
386 * @param minIdx Minimum index to start searching from.
387 * @param maxIdx Maximum index to search up to.
388 * @param length Length of the region to find.
389 * @param alignment Alignment of the region.
390 * @return Starting index of the found region, or `map->length` if not found.
391 */
393 uint64_t length, uint64_t alignment)
394{
395 if (length == 0 || minIdx >= maxIdx || maxIdx > map->length)
396 {
397 return map->length;
398 }
399
400 if (alignment == 0)
401 {
402 alignment = 1;
403 }
404
405 uint64_t idx = MAX(minIdx, map->firstZeroIdx);
406 idx = ROUND_UP(idx, alignment);
407
408 while (idx <= maxIdx - length)
409 {
410 uint64_t firstSet = bitmap_find_first_set(map, idx, idx + length);
411 if (firstSet >= idx + length)
412 {
413 bitmap_set_range(map, idx, idx + length);
414 return idx;
415 }
416 idx = ROUND_UP(firstSet + 1, alignment);
417 }
418
419 return map->length;
420}
421
422/** @} */
423
424#endif // _SYS_BITMAP_H
boot_memory_map_t * map
Definition main.c:241
EFI_PHYSICAL_ADDRESS buffer
Definition main.c:237
static uint64_t bitmap_find_first_set(bitmap_t *map, uint64_t startIdx, uint64_t endIdx)
Find the first set bit in the bitmap.
Definition bitmap.h:350
static uint64_t bitmap_find_first_clear(bitmap_t *map, uint64_t startIdx, uint64_t endIdx)
Find the first clear bit in the bitmap.
Definition bitmap.h:306
static bool bitmap_is_empty(bitmap_t *map)
Check if the bitmap is empty (all bits clear).
Definition bitmap.h:141
static uint64_t bitmap_find_clear_region_and_set(bitmap_t *map, uint64_t minIdx, uintptr_t maxIdx, uint64_t length, uint64_t alignment)
Find a clear region of specified length and alignment, and set it.
Definition bitmap.h:392
static void bitmap_clear(bitmap_t *map, uint64_t index)
Clear a bit in the bitmap.
Definition bitmap.h:244
static bool bitmap_is_set(bitmap_t *map, uint64_t idx)
Check if a bit is set in the bitmap.
Definition bitmap.h:172
static void bitmap_set(bitmap_t *map, uint64_t index)
Set a bit in the bitmap.
Definition bitmap.h:190
static void bitmap_init(bitmap_t *map, void *buffer, uint64_t length)
Initialize a bitmap.
Definition bitmap.h:128
#define BITMAP_BITS_TO_QWORDS(bits)
Convert number of bits to number of qwords.
Definition bitmap.h:34
static void bitmap_set_range(bitmap_t *map, uint64_t low, uint64_t high)
Set a range of bits in the bitmap.
Definition bitmap.h:209
static void bitmap_clear_range(bitmap_t *map, uint64_t low, uint64_t high)
Clear a range of bits in the bitmap.
Definition bitmap.h:264
#define MIN(x, y)
Definition math.h:18
#define ROUND_UP(number, multiple)
Definition math.h:21
#define MAX(x, y)
Definition math.h:17
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
Bitmap structure.
Definition bitmap.h:22
uint64_t * buffer
Definition bitmap.h:25
uint64_t length
Definition bitmap.h:24
uint64_t firstZeroIdx
Definition bitmap.h:23