Line data Source code
1 1 : /*
2 : * Copyright (c) 2021 Intel Corporation
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /**
8 : * @file
9 : *
10 : * @brief Memory Blocks Allocator
11 : */
12 :
13 : #ifndef ZEPHYR_INCLUDE_SYS_MEM_BLOCKS_H_
14 : #define ZEPHYR_INCLUDE_SYS_MEM_BLOCKS_H_
15 :
16 : #ifdef __cplusplus
17 : extern "C" {
18 : #endif
19 :
20 : #include <stddef.h>
21 : #include <stdint.h>
22 :
23 : #include <zephyr/kernel.h>
24 : #include <zephyr/math/ilog2.h>
25 : #include <zephyr/sys/bitarray.h>
26 : #include <zephyr/sys/mem_stats.h>
27 :
28 0 : #define MAX_MULTI_ALLOCATORS 8
29 :
30 : /**
31 : * @defgroup mem_blocks_apis Memory Blocks APIs
32 : * @ingroup memory_management
33 : * @{
34 : */
35 :
36 : /**
37 : * @brief Memory Blocks Allocator
38 : */
39 : struct sys_mem_blocks;
40 :
41 : /**
42 : * @brief Multi Memory Blocks Allocator
43 : */
44 : struct sys_multi_mem_blocks;
45 :
46 : /**
47 : * @typedef sys_mem_blocks_t
48 : *
49 : * @brief Memory Blocks Allocator
50 : */
51 1 : typedef struct sys_mem_blocks sys_mem_blocks_t;
52 :
53 : /**
54 : * @typedef sys_multi_mem_blocks_t
55 : *
56 : * @brief Multi Memory Blocks Allocator
57 : */
58 1 : typedef struct sys_multi_mem_blocks sys_multi_mem_blocks_t;
59 :
60 : /**
61 : * @brief Multi memory blocks allocator choice function
62 : *
63 : * This is a user-provided functions whose responsibility is selecting
64 : * a specific memory blocks allocator based on the opaque cfg value,
65 : * which is specified by the user as an argument to
66 : * sys_multi_mem_blocks_alloc(). The callback returns a pointer to
67 : * the chosen allocator where the allocation is performed.
68 : *
69 : * NULL may be returned, which will cause the
70 : * allocation to fail and a -EINVAL reported to the calling code.
71 : *
72 : * @param group Multi memory blocks allocator structure.
73 : * @param cfg An opaque user-provided value. It may be interpreted in
74 : * any way by the application.
75 : *
76 : * @return A pointer to the chosen allocator, or NULL if none is chosen.
77 : */
78 1 : typedef sys_mem_blocks_t *(*sys_multi_mem_blocks_choice_fn_t)
79 : (struct sys_multi_mem_blocks *group, void *cfg);
80 :
81 : /**
82 : * @cond INTERNAL_HIDDEN
83 : */
84 :
85 : struct sys_mem_blocks_info {
86 : uint32_t num_blocks; /* Total number of blocks */
87 : uint8_t blk_sz_shift; /* Bit shift for block size */
88 : #ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
89 : uint32_t used_blocks; /* Current number of blocks in use */
90 : uint32_t max_used_blocks; /* Maximum number of blocks in use */
91 : #endif
92 : };
93 :
94 : struct sys_mem_blocks {
95 : struct sys_mem_blocks_info info;
96 :
97 : /* Memory block buffer */
98 : uint8_t *buffer;
99 :
100 : /* Bitmap of allocated blocks */
101 : sys_bitarray_t *bitmap;
102 :
103 : #ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
104 : /* Spinlock guarding access to memory block internals */
105 : struct k_spinlock lock;
106 : #endif
107 : #ifdef CONFIG_OBJ_CORE_SYS_MEM_BLOCKS
108 : struct k_obj_core obj_core;
109 : #endif
110 : };
111 :
112 : struct sys_multi_mem_blocks {
113 : /* Number of allocators in this group */
114 : int num_allocators;
115 : sys_multi_mem_blocks_choice_fn_t choice_fn;
116 : sys_mem_blocks_t *allocators[MAX_MULTI_ALLOCATORS];
117 : };
118 :
119 : /**
120 : * @brief Create a memory block object with a providing backing buffer.
121 : *
122 : * @param name Name of the memory block object.
123 : * @param blk_sz Size of each memory block (in bytes, power of 2).
124 : * @param num_blks Total number of memory blocks.
125 : * @param buf Backing buffer of type uint8_t.
126 : * @param mbmod Modifier to the memory block struct
127 : */
128 : #define _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf, mbmod) \
129 : _SYS_BITARRAY_DEFINE(_sys_mem_blocks_bitmap_##name, \
130 : num_blks, mbmod); \
131 : mbmod struct sys_mem_blocks name = { \
132 : .info = {num_blks, ilog2(blk_sz)}, \
133 : .buffer = buf, \
134 : .bitmap = &_sys_mem_blocks_bitmap_##name, \
135 : }; \
136 : STRUCT_SECTION_ITERABLE_ALTERNATE(sys_mem_blocks_ptr, \
137 : sys_mem_blocks *, \
138 : __##name##_ptr) = &name; \
139 : LINKER_KEEP(__##name##_ptr);
140 :
141 : /**
142 : * @brief Create a memory block object with a new backing buffer.
143 : *
144 : * @param name Name of the memory block object.
145 : * @param blk_sz Size of each memory block (in bytes, power of 2).
146 : * @param num_blks Total number of memory blocks.
147 : * @param balign Alignment of the memory block buffer (power of 2).
148 : * @param mbmod Modifier to the memory block struct
149 : */
150 : #define _SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, balign, mbmod) \
151 : mbmod uint8_t __noinit_named(sys_mem_blocks_buf_##name) \
152 : __aligned(WB_UP(balign)) \
153 : _sys_mem_blocks_buf_##name[num_blks * WB_UP(blk_sz)]; \
154 : _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, \
155 : _sys_mem_blocks_buf_##name, \
156 : mbmod);
157 :
158 : /**
159 : * INTERNAL_HIDDEN @endcond
160 : */
161 :
162 : /**
163 : * @brief Create a memory block object with a new backing buffer.
164 : *
165 : * @param name Name of the memory block object.
166 : * @param blk_sz Size of each memory block (in bytes).
167 : * @param num_blks Total number of memory blocks.
168 : * @param buf_align Alignment of the memory block buffer (power of 2).
169 : */
170 1 : #define SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, buf_align) \
171 : _SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, buf_align,)
172 :
173 : /**
174 : * @brief Create a static memory block object with a new backing buffer.
175 : *
176 : * @param name Name of the memory block object.
177 : * @param blk_sz Size of each memory block (in bytes).
178 : * @param num_blks Total number of memory blocks.
179 : * @param buf_align Alignment of the memory block buffer (power of 2).
180 : */
181 1 : #define SYS_MEM_BLOCKS_DEFINE_STATIC(name, blk_sz, num_blks, buf_align) \
182 : _SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, buf_align, static)
183 :
184 :
185 : /**
186 : * @brief Create a memory block object with a providing backing buffer.
187 : *
188 : * @param name Name of the memory block object.
189 : * @param blk_sz Size of each memory block (in bytes).
190 : * @param num_blks Total number of memory blocks.
191 : * @param buf Backing buffer of type uint8_t.
192 : */
193 1 : #define SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf) \
194 : _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf,)
195 :
196 : /**
197 : * @brief Create a static memory block object with a providing backing buffer.
198 : *
199 : * @param name Name of the memory block object.
200 : * @param blk_sz Size of each memory block (in bytes).
201 : * @param num_blks Total number of memory blocks.
202 : * @param buf Backing buffer of type uint8_t.
203 : */
204 1 : #define SYS_MEM_BLOCKS_DEFINE_STATIC_WITH_EXT_BUF(name, blk_sz, num_blks, buf) \
205 : _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf, static)
206 :
207 : /**
208 : * @brief Allocate multiple memory blocks
209 : *
210 : * Allocate multiple memory blocks, and place their pointers into
211 : * the output array.
212 : *
213 : * @param[in] mem_block Pointer to memory block object.
214 : * @param[in] count Number of blocks to allocate.
215 : * @param[out] out_blocks Output array to be populated by pointers to
216 : * the memory blocks. It must have at least
217 : * @p count elements.
218 : *
219 : * @retval 0 Successful
220 : * @retval -EINVAL Invalid argument supplied.
221 : * @retval -ENOMEM Not enough blocks for allocation.
222 : */
223 1 : int sys_mem_blocks_alloc(sys_mem_blocks_t *mem_block, size_t count,
224 : void **out_blocks);
225 :
226 : /**
227 : * @brief Allocate a contiguous set of memory blocks
228 : *
229 : * Allocate multiple memory blocks, and place their pointers into
230 : * the output array.
231 : *
232 : * @param[in] mem_block Pointer to memory block object.
233 : * @param[in] count Number of blocks to allocate.
234 : * @param[out] out_block Output pointer to the start of the allocated block set
235 : *
236 : * @retval 0 Successful
237 : * @retval -EINVAL Invalid argument supplied.
238 : * @retval -ENOMEM Not enough contiguous blocks for allocation.
239 : */
240 1 : int sys_mem_blocks_alloc_contiguous(sys_mem_blocks_t *mem_block, size_t count,
241 : void **out_block);
242 :
243 : /**
244 : * @brief Force allocation of a specified blocks in a memory block object
245 : *
246 : * Allocate a specified blocks in a memory block object.
247 : * Note: use caution when mixing sys_mem_blocks_get and sys_mem_blocks_alloc,
248 : * allocation may take any of the free memory space
249 : *
250 : *
251 : * @param[in] mem_block Pointer to memory block object.
252 : * @param[in] in_block Address of the first required block to allocate
253 : * @param[in] count Number of blocks to allocate.
254 : *
255 : * @retval 0 Successful
256 : * @retval -EINVAL Invalid argument supplied.
257 : * @retval -ENOMEM Some of blocks are taken and cannot be allocated
258 : */
259 1 : int sys_mem_blocks_get(sys_mem_blocks_t *mem_block, void *in_block, size_t count);
260 :
261 : /**
262 : * @brief check if the region is free
263 : *
264 : * @param[in] mem_block Pointer to memory block object.
265 : * @param[in] in_block Address of the first block to check
266 : * @param[in] count Number of blocks to check.
267 : *
268 : * @retval 1 All memory blocks are free
269 : * @retval 0 At least one of the memory blocks is taken
270 : */
271 1 : int sys_mem_blocks_is_region_free(sys_mem_blocks_t *mem_block, void *in_block, size_t count);
272 :
273 : /**
274 : * @brief Free multiple memory blocks
275 : *
276 : * Free multiple memory blocks according to the array of memory
277 : * block pointers.
278 : *
279 : * @param[in] mem_block Pointer to memory block object.
280 : * @param[in] count Number of blocks to free.
281 : * @param[in] in_blocks Input array of pointers to the memory blocks.
282 : *
283 : * @retval 0 Successful
284 : * @retval -EINVAL Invalid argument supplied.
285 : * @retval -EFAULT Invalid pointers supplied.
286 : */
287 1 : int sys_mem_blocks_free(sys_mem_blocks_t *mem_block, size_t count,
288 : void **in_blocks);
289 :
290 : /**
291 : * @brief Free contiguous multiple memory blocks
292 : *
293 : * Free contiguous multiple memory blocks
294 : *
295 : * @param[in] mem_block Pointer to memory block object.
296 : * @param[in] block Pointer to the first memory block
297 : * @param[in] count Number of blocks to free.
298 : *
299 : * @retval 0 Successful
300 : * @retval -EINVAL Invalid argument supplied.
301 : * @retval -EFAULT Invalid pointer supplied.
302 : */
303 1 : int sys_mem_blocks_free_contiguous(sys_mem_blocks_t *mem_block, void *block, size_t count);
304 :
305 : #ifdef CONFIG_SYS_MEM_BLOCKS_RUNTIME_STATS
306 : /**
307 : * @brief Get the runtime statistics of a memory block
308 : *
309 : * This function retrieves the runtime stats for the specified memory block
310 : * @a mem_block and copies it into the memory pointed to by @a stats.
311 : *
312 : * @param mem_block Pointer to system memory block
313 : * @param stats Pointer to struct to copy statistics into
314 : *
315 : * @return -EINVAL if NULL pointer was passed, otherwise 0
316 : */
317 : int sys_mem_blocks_runtime_stats_get(sys_mem_blocks_t *mem_block,
318 : struct sys_memory_stats *stats);
319 :
320 : /**
321 : * @brief Reset the maximum memory block usage
322 : *
323 : * This routine resets the maximum memory usage in the specified memory
324 : * block @a mem_block to match that block's current memory usage.
325 : *
326 : * @param mem_block Pointer to system memory block
327 : *
328 : * @return -EINVAL if NULL pointer was passed, otherwise 0
329 : */
330 : int sys_mem_blocks_runtime_stats_reset_max(sys_mem_blocks_t *mem_block);
331 : #endif
332 :
333 : /**
334 : * @brief Initialize multi memory blocks allocator group
335 : *
336 : * Initialize a sys_multi_mem_block struct with the specified choice
337 : * function. Note that individual allocator must be added later with
338 : * sys_multi_mem_blocks_add_allocator.
339 : *
340 : * @param group Multi memory blocks allocator structure.
341 : * @param choice_fn A sys_multi_mem_blocks_choice_fn_t callback used to
342 : * select the allocator to be used at allocation time
343 : */
344 1 : void sys_multi_mem_blocks_init(sys_multi_mem_blocks_t *group,
345 : sys_multi_mem_blocks_choice_fn_t choice_fn);
346 :
347 : /**
348 : * @brief Add an allocator to an allocator group
349 : *
350 : * This adds a known allocator to an existing multi memory blocks
351 : * allocator group.
352 : *
353 : * @param group Multi memory blocks allocator structure.
354 : * @param alloc Allocator to add
355 : */
356 1 : void sys_multi_mem_blocks_add_allocator(sys_multi_mem_blocks_t *group,
357 : sys_mem_blocks_t *alloc);
358 :
359 : /**
360 : * @brief Allocate memory from multi memory blocks allocator group
361 : *
362 : * Just as for sys_mem_blocks_alloc(), allocates multiple blocks of
363 : * memory. Takes an opaque configuration pointer passed to the choice
364 : * function, which is used by integration code to choose an allocator.
365 : *
366 : * @param[in] group Multi memory blocks allocator structure.
367 : * @param[in] cfg Opaque configuration parameter,
368 : * as for sys_multi_mem_blocks_choice_fn_t
369 : * @param[in] count Number of blocks to allocate
370 : * @param[out] out_blocks Output array to be populated by pointers to
371 : * the memory blocks. It must have at least
372 : * @p count elements.
373 : * @param[out] blk_size If not NULL, output the block size of
374 : * the chosen allocator.
375 : *
376 : * @retval 0 Successful
377 : * @retval -EINVAL Invalid argument supplied, or no allocator chosen.
378 : * @retval -ENOMEM Not enough blocks for allocation.
379 : */
380 1 : int sys_multi_mem_blocks_alloc(sys_multi_mem_blocks_t *group,
381 : void *cfg, size_t count,
382 : void **out_blocks,
383 : size_t *blk_size);
384 :
385 : /**
386 : * @brief Free memory allocated from multi memory blocks allocator group
387 : *
388 : * Free previous allocated memory blocks from sys_multi_mem_blocks_alloc().
389 : *
390 : * Note that all blocks in @p in_blocks must be from the same allocator.
391 : *
392 : * @param[in] group Multi memory blocks allocator structure.
393 : * @param[in] count Number of blocks to free.
394 : * @param[in] in_blocks Input array of pointers to the memory blocks.
395 : *
396 : * @retval 0 Successful
397 : * @retval -EINVAL Invalid argument supplied, or no allocator chosen.
398 : * @retval -EFAULT Invalid pointer(s) supplied.
399 : */
400 1 : int sys_multi_mem_blocks_free(sys_multi_mem_blocks_t *group,
401 : size_t count, void **in_blocks);
402 :
403 : /** @} */
404 :
405 : #ifdef __cplusplus
406 : }
407 : #endif
408 :
409 : #endif /* ZEPHYR_INCLUDE_SYS_MEM_BLOCKS_H_ */
|