1 /* Copyright (c) 2021 Intel Corporation
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 
5 #ifndef ZEPHYR_INCLUDE_SYS_MULTI_HEAP_H_
6 #define ZEPHYR_INCLUDE_SYS_MULTI_HEAP_H_
7 
8 #include <zephyr/types.h>
9 
10 #define MAX_MULTI_HEAPS 8
11 
12 /**
13  * @defgroup multi_heap_wrapper Multi-Heap Wrapper
14  * @ingroup heaps
15  * @{
16  */
17 
18 /**
19  * @brief Multi-heap allocator
20  *
21  * A sys_multi_heap represents a single allocator made from multiple,
22  * separately managed pools of memory that must be accessed via a
23  * unified API.  They can be discontiguous, and in many cases will be
24  * expected to have different capabilities (for example: latency,
25  * cacheability, cpu affinity, etc...)
26  *
27  * Allocation from the multiheap provides an opaque "configuration"
28  * value to specify requirements and heuristics to assist the choice
29  * in backend, which is then provided to a user-specified "choice"
30  * function whose job it is to select a heap based on information in
31  * the config specifier and runtime state (heap full state, etc...)
32  */
33 struct sys_multi_heap;
34 
35 /**
36  * @brief Multi-heap choice function
37  *
38  * This is a user-provided functions whose responsibility is selecting
39  * a specific sys_heap backend based on the opaque cfg value, which is
40  * specified by the user as an argument to sys_multi_heap_alloc(), and
41  * performing the allocation on behalf of the caller.  The callback is
42  * free to choose any registered heap backend to perform the
43  * allocation, and may choose to pad the user-provided values as
44  * needed, and to use an aligned allocation where required by the
45  * specified configuration.
46  *
47  * NULL may be returned, which will cause the
48  * allocation to fail and a NULL reported to the calling code.
49  *
50  * @param mheap Multi-heap structure.
51  * @param cfg An opaque user-provided value.  It may be interpreted in
52  *            any way by the application
53  * @param align Alignment of requested memory (or zero for no alignment)
54  * @param size The user-specified allocation size in bytes
55  * @return A pointer to the allocated memory
56  */
57 typedef void *(*sys_multi_heap_fn_t)(struct sys_multi_heap *mheap, void *cfg,
58 				     size_t align, size_t size);
59 
60 
61 struct sys_multi_heap_rec {
62 	struct sys_heap *heap;
63 	void *user_data;
64 };
65 
66 struct sys_multi_heap {
67 	unsigned int nheaps;
68 	sys_multi_heap_fn_t choice;
69 	struct sys_multi_heap_rec heaps[MAX_MULTI_HEAPS];
70 };
71 
72 /**
73  * @brief Initialize multi-heap
74  *
75  * Initialize a sys_multi_heap struct with the specified choice
76  * function.  Note that individual heaps must be added later with
77  * sys_multi_heap_add_heap so that the heap bounds can be tracked by
78  * the multi heap code.
79  *
80  * @note In general a multiheap is likely to be instantiated
81  * semi-statically from system configuration (for example, via
82  * linker-provided bounds on available memory in different regions, or
83  * from devicetree definitions of hardware-provided addressable
84  * memory, etc...).  The general expectation is that a soc- or
85  * board-level platform device will be initialized at system boot from
86  * these upstream configuration sources and not that an application
87  * will assemble a multi-heap on its own.
88  *
89  * @param heap A sys_multi_heap to initialize
90  * @param choice_fn A sys_multi_heap_fn_t callback used to select
91  *                  heaps at allocation time
92  */
93 void sys_multi_heap_init(struct sys_multi_heap *heap,
94 			 sys_multi_heap_fn_t choice_fn);
95 
96 /**
97  * @brief Add sys_heap to multi heap
98  *
99  * This adds a known sys_heap backend to an existing multi heap,
100  * allowing the multi heap internals to track the bounds of the heap
101  * and determine which heap (if any) from which a freed block was
102  * allocated.
103  *
104  * @param mheap A sys_multi_heap to which to add a heap
105  * @param heap The heap to add
106  * @param user_data pointer to any data for the heap
107  */
108 void sys_multi_heap_add_heap(struct sys_multi_heap *mheap, struct sys_heap *heap, void *user_data);
109 
110 /**
111  * @brief Allocate memory from multi heap
112  *
113  * Just as for sys_heap_alloc(), allocates a block of memory of the
114  * specified size in bytes.  Takes an opaque configuration pointer
115  * passed to the multi heap choice function, which is used by
116  * integration code to choose a heap backend.
117  *
118  * @param mheap Multi heap pointer
119  * @param cfg Opaque configuration parameter, as for sys_multi_heap_fn_t
120  * @param bytes Requested size of the allocation, in bytes
121  * @return A valid pointer to heap memory, or NULL if no memory is available
122  */
123 void *sys_multi_heap_alloc(struct sys_multi_heap *mheap, void *cfg, size_t bytes);
124 
125 /**
126  * @brief Allocate aligned memory from multi heap
127  *
128  * Just as for sys_multi_heap_alloc(), allocates a block of memory of
129  * the specified size in bytes.  Takes an additional parameter
130  * specifying a power of two alignment, in bytes.
131  *
132  * @param mheap Multi heap pointer
133  * @param cfg Opaque configuration parameter, as for sys_multi_heap_fn_t
134  * @param align Power of two alignment for the returned pointer, in bytes
135  * @param bytes Requested size of the allocation, in bytes
136  * @return A valid pointer to heap memory, or NULL if no memory is available
137  */
138 void *sys_multi_heap_aligned_alloc(struct sys_multi_heap *mheap,
139 				   void *cfg, size_t align, size_t bytes);
140 
141 /**
142  * @brief Get a specific heap for provided address
143  *
144  * Finds a single system heap (with user_data)
145  * controlling the provided pointer
146  *
147  * @param mheap Multi heap pointer
148  * @param addr address to be found, must be a pointer to a block allocated by sys_multi_heap_alloc
149  * @return 0 multi_heap_rec pointer to a structure to be filled with return data
150  *			 or NULL if the heap has not been found
151  */
152 const struct sys_multi_heap_rec *sys_multi_heap_get_heap(const struct sys_multi_heap *mheap,
153 							 void *addr);
154 
155 /**
156  * @brief Free memory allocated from multi heap
157  *
158  * Returns the specified block, which must be the return value of a
159  * previously successful sys_multi_heap_alloc() or
160  * sys_multi_heap_aligned_alloc() call, to the heap backend from which
161  * it was allocated.
162  *
163  * Accepts NULL as a block parameter, which is specified to have no
164  * effect.
165  *
166  * @param mheap Multi heap pointer
167  * @param block Block to free, must be a pointer to a block allocated by sys_multi_heap_alloc
168  */
169 void sys_multi_heap_free(struct sys_multi_heap *mheap, void *block);
170 
171 /**
172  * @}
173  */
174 
175 #endif /* ZEPHYR_INCLUDE_SYS_MULTI_HEAP_H_ */
176