/* * Copyright (c) 2021 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * * @brief Memory Blocks Allocator */ #ifndef ZEPHYR_INCLUDE_SYS_MEM_BLOCKS_H_ #define ZEPHYR_INCLUDE_SYS_MEM_BLOCKS_H_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #define MAX_MULTI_ALLOCATORS 8 /** * @defgroup mem_blocks_apis Memory Blocks APIs * @{ */ /** * @brief Memory Blocks Allocator */ struct sys_mem_blocks; /** * @brief Multi Memory Blocks Allocator */ struct sys_multi_mem_blocks; /** * @typedef sys_mem_blocks_t * * @brief Memory Blocks Allocator */ typedef struct sys_mem_blocks sys_mem_blocks_t; /** * @typedef sys_multi_mem_blocks_t * * @brief Multi Memory Blocks Allocator */ typedef struct sys_multi_mem_blocks sys_multi_mem_blocks_t; /** * @brief Multi memory blocks allocator choice function * * This is a user-provided functions whose responsibility is selecting * a specific memory blocks allocator based on the opaque cfg value, * which is specified by the user as an argument to * sys_multi_mem_blocks_alloc(). The callback returns a pointer to * the chosen allocator where the allocation is performed. * * NULL may be returned, which will cause the * allocation to fail and a -EINVAL reported to the calling code. * * @param group Multi memory blocks allocator structure. * @param cfg An opaque user-provided value. It may be interpreted in * any way by the application. * * @return A pointer to the chosen allocator, or NULL if none is chosen. */ typedef sys_mem_blocks_t *(*sys_multi_mem_blocks_choice_fn_t) (struct sys_multi_mem_blocks *group, void *cfg); /** * @cond INTERNAL_HIDDEN */ struct sys_mem_blocks { /* Number of blocks */ uint32_t num_blocks; /* Bit shift for block size */ uint8_t blk_sz_shift; /* Memory block buffer */ uint8_t *buffer; /* Bitmap of allocated blocks */ sys_bitarray_t *bitmap; }; struct sys_multi_mem_blocks { /* Number of allocators in this group */ int num_allocators; sys_multi_mem_blocks_choice_fn_t choice_fn; sys_mem_blocks_t *allocators[MAX_MULTI_ALLOCATORS]; }; /** * @def _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF * * @brief Create a memory block object with a providing backing buffer. * * @param name Name of the memory block object. * @param blk_sz Size of each memory block (in bytes, power of 2). * @param num_blks Total number of memory blocks. * @param buf Backing buffer of type uint8_t. * @param mbmod Modifier to the memory block struct */ #define _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf, mbmod) \ _SYS_BITARRAY_DEFINE(_sys_mem_blocks_bitmap_##name, \ num_blks, mbmod); \ mbmod sys_mem_blocks_t name = { \ .num_blocks = num_blks, \ .blk_sz_shift = ilog2(blk_sz), \ .buffer = buf, \ .bitmap = &_sys_mem_blocks_bitmap_##name, \ } /** * @def _SYS_MEM_BLOCKS_DEFINE * * @brief Create a memory block object with a new backing buffer. * * @param name Name of the memory block object. * @param blk_sz Size of each memory block (in bytes, power of 2). * @param num_blks Total number of memory blocks. * @param balign Alignment of the memory block buffer (power of 2). * @param mbmod Modifier to the memory block struct */ #define _SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, balign, mbmod) \ mbmod uint8_t __noinit_named(sys_mem_blocks_buf_##name) \ __aligned(WB_UP(balign)) \ _sys_mem_blocks_buf_##name[num_blks * WB_UP(blk_sz)]; \ _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, \ _sys_mem_blocks_buf_##name, \ mbmod); /** * INTERNAL_HIDDEN @endcond */ /** * @def SYS_MEM_BLOCKS_DEFINE * * @brief Create a memory block object with a new backing buffer. * * @param name Name of the memory block object. * @param blk_sz Size of each memory block (in bytes). * @param num_blks Total number of memory blocks. * @param buf_align Alignment of the memory block buffer (power of 2). */ #define SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, buf_align) \ _SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, buf_align,) /** * @def SYS_MEM_BLOCKS_DEFINE_STATIC * * @brief Create a static memory block object with a new backing buffer. * * @param name Name of the memory block object. * @param blk_sz Size of each memory block (in bytes). * @param num_blks Total number of memory blocks. * @param buf_align Alignment of the memory block buffer (power of 2). */ #define SYS_MEM_BLOCKS_DEFINE_STATIC(name, blk_sz, num_blks, buf_align) \ _SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, buf_align, static) /** * @def SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF * * @brief Create a memory block object with a providing backing buffer. * * @param name Name of the memory block object. * @param blk_sz Size of each memory block (in bytes). * @param num_blks Total number of memory blocks. * @param buf Backing buffer of type uint8_t. */ #define SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf) \ _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf,) /** * @def SYS_MEM_BLOCKS_DEFINE_STATIC_WITH_EXT_BUF * * @brief Create a static memory block object with a providing backing buffer. * * @param name Name of the memory block object. * @param blk_sz Size of each memory block (in bytes). * @param num_blks Total number of memory blocks. * @param buf Backing buffer of type uint8_t. */ #define SYS_MEM_BLOCKS_DEFINE_STATIC_WITH_EXT_BUF(name, blk_sz, num_blks, buf) \ _SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf, static) /** * @brief Allocate multiple memory blocks * * Allocate multiple memory blocks, and place their pointers into * the output array. * * @param[in] mem_block Pointer to memory block object. * @param[in] count Number of blocks to allocate. * @param[out] out_blocks Output array to be populated by pointers to * the memory blocks. It must have at least * @p count elements. * * @retval 0 Successful * @retval -EINVAL Invalid argument supplied. * @retval -ENOMEM Not enough blocks for allocation. */ int sys_mem_blocks_alloc(sys_mem_blocks_t *mem_block, size_t count, void **out_blocks); /** * @brief Free multiple memory blocks * * Free multiple memory blocks according to the array of memory * block pointers. * * @param[in] mem_block Pointer to memory block object. * @param[in] count Number of blocks to free. * @param[in] in_blocks Input array of pointers to the memory blocks. * * @retval 0 Successful * @retval -EINVAL Invalid argument supplied. * @retval -EFAULT Invalid pointers supplied. */ int sys_mem_blocks_free(sys_mem_blocks_t *mem_block, size_t count, void **in_blocks); /** * @brief Initialize multi memory blocks allocator group * * Initialize a sys_multi_mem_block struct with the specified choice * function. Note that individual allocator must be added later with * sys_multi_mem_blocks_add_allocator. * * @param group Multi memory blocks allocator structure. * @param choice_fn A sys_multi_mem_blocks_choice_fn_t callback used to * select the allocator to be used at allocation time */ void sys_multi_mem_blocks_init(sys_multi_mem_blocks_t *group, sys_multi_mem_blocks_choice_fn_t choice_fn); /** * @brief Add an allocator to an allocator group * * This adds a known allocator to an existing multi memory blocks * allocator group. * * @param group Multi memory blocks allocator structure. * @param alloc Allocator to add */ void sys_multi_mem_blocks_add_allocator(sys_multi_mem_blocks_t *group, sys_mem_blocks_t *alloc); /** * @brief Allocate memory from multi memory blocks allocator group * * Just as for sys_mem_blocks_alloc(), allocates multiple blocks of * memory. Takes an opaque configuration pointer passed to the choice * function, which is used by integration code to choose an allocator. * * @param[in] group Multi memory blocks allocator structure. * @param[in] cfg Opaque configuration parameter, * as for sys_multi_mem_blocks_choice_fn_t * @param[in] count Number of blocks to allocate * @param[out] out_blocks Output array to be populated by pointers to * the memory blocks. It must have at least * @p count elements. * @param[out] blk_size If not NULL, output the block size of * the chosen allocator. * * @retval 0 Successful * @retval -EINVAL Invalid argument supplied, or no allocator chosen. * @retval -ENOMEM Not enough blocks for allocation. */ int sys_multi_mem_blocks_alloc(sys_multi_mem_blocks_t *group, void *cfg, size_t count, void **out_blocks, size_t *blk_size); /** * @brief Free memory allocated from multi memory blocks allocator group * * Free previous allocated memory blocks from sys_multi_mem_blocks_alloc(). * * Note that all blocks in @p in_blocks must be from the same allocator. * * @param[in] group Multi memory blocks allocator structure. * @param[in] count Number of blocks to free. * @param[in] in_blocks Input array of pointers to the memory blocks. * * @retval 0 Successful * @retval -EINVAL Invalid argument supplied, or no allocator chosen. * @retval -EFAULT Invalid pointer(s) supplied. */ int sys_multi_mem_blocks_free(sys_multi_mem_blocks_t *group, size_t count, void **in_blocks); /** @} */ #ifdef __cplusplus } #endif #endif /* ZEPHYR_INCLUDE_SYS_MEM_BLOCKS_H_ */