1 /*
2  * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdbool.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/math_extras.h>
12 #include <esp_attr.h>
13 #include <esp_heap_caps.h>
14 
15 #if (CONFIG_ESP_HEAP_MEM_POOL_REGION_1_SIZE > 0)
16 char __aligned(sizeof(void *)) __NOINIT_ATTR dram0_seg_1_heap[CONFIG_ESP_HEAP_MEM_POOL_REGION_1_SIZE];
17 STRUCT_SECTION_ITERABLE(k_heap, _internal_heap_1) = {
18     .heap = {
19         .init_mem = dram0_seg_1_heap,
20         .init_bytes = CONFIG_ESP_HEAP_MEM_POOL_REGION_1_SIZE,
21     }
22 };
23 #endif /* CONFIG_ESP_HEAP_MEM_POOL_REGION_1_SIZE > 0 */
24 
25 static esp_alloc_failed_hook_t alloc_failed_callback;
26 
heap_caps_register_failed_alloc_callback(esp_alloc_failed_hook_t callback)27 esp_err_t heap_caps_register_failed_alloc_callback(esp_alloc_failed_hook_t callback)
28 {
29     if (callback == NULL) {
30         return ESP_ERR_INVALID_ARG;
31     }
32 
33     alloc_failed_callback = callback;
34 
35     return ESP_OK;
36 }
37 
heap_caps_alloc_failed(size_t requested_size,uint32_t caps,const char * function_name)38 static void heap_caps_alloc_failed(size_t requested_size, uint32_t caps, const char *function_name)
39 {
40     if (alloc_failed_callback) {
41         alloc_failed_callback(requested_size, caps, function_name);
42     }
43 
44 #ifdef CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS
45     esp_system_abort("Memory allocation failed");
46 #endif
47 }
48 
49 /*
50 Routine to allocate a bit of memory with certain capabilities. caps is a bitfield of MALLOC_CAP_* bits.
51 */
heap_caps_malloc_base(size_t size,uint32_t caps)52 static void *heap_caps_malloc_base( size_t size, uint32_t caps)
53 {
54 
55     void *ptr = k_malloc(size);
56 
57     if (!ptr && size > 0) {
58         heap_caps_alloc_failed(size, caps, __func__);
59     }
60 
61     return ptr;
62 }
63 
heap_caps_malloc(size_t size,uint32_t caps)64 void *heap_caps_malloc( size_t size, uint32_t caps)
65 {
66     return heap_caps_malloc_base(size, caps);
67 }
68 
heap_caps_malloc_extmem_enable(size_t limit)69 void heap_caps_malloc_extmem_enable(size_t limit)
70 {
71     (void)limit;
72     // Not implemented
73 }
74 
heap_caps_malloc_default(size_t size)75 void *heap_caps_malloc_default( size_t size )
76 {
77     return heap_caps_malloc_base(size, MALLOC_CAP_DEFAULT);
78 }
79 
heap_caps_malloc_prefer(size_t size,size_t num,...)80 void *heap_caps_malloc_prefer( size_t size, size_t num, ... )
81 {
82     return heap_caps_malloc(size, MALLOC_CAP_DEFAULT);
83 }
84 
85 
heap_caps_realloc_base(void * ptr,size_t size,uint32_t caps)86 static void *heap_caps_realloc_base( void *ptr, size_t size, uint32_t caps)
87 {
88     ptr = k_realloc(ptr, size);
89 
90     if (ptr == NULL && size > 0) {
91         heap_caps_alloc_failed(size, caps, __func__);
92     }
93 
94     return ptr;
95 }
96 
heap_caps_realloc(void * ptr,size_t size,uint32_t caps)97 void *heap_caps_realloc( void *ptr, size_t size, uint32_t caps)
98 {
99     return heap_caps_realloc_base(ptr, size, caps);
100 }
101 
heap_caps_realloc_default(void * ptr,size_t size)102 void *heap_caps_realloc_default( void *ptr, size_t size )
103 {
104     return heap_caps_realloc_base(ptr, size, MALLOC_CAP_DEFAULT);
105 }
106 
heap_caps_realloc_prefer(void * ptr,size_t size,size_t num,...)107 void *heap_caps_realloc_prefer( void *ptr, size_t size, size_t num, ... )
108 {
109     return heap_caps_realloc_base(ptr, size, MALLOC_CAP_DEFAULT);
110 }
111 
heap_caps_free(void * ptr)112 void heap_caps_free( void *ptr)
113 {
114     k_free(ptr);
115 }
116 
heap_caps_calloc_base(size_t n,size_t size,uint32_t caps)117 static void *heap_caps_calloc_base( size_t n, size_t size, uint32_t caps)
118 {
119     size_t size_bytes;
120 
121     if (__builtin_mul_overflow(n, size, &size_bytes)) {
122         return NULL;
123     }
124 
125     return k_calloc(n, size);
126 }
127 
heap_caps_calloc(size_t n,size_t size,uint32_t caps)128 void *heap_caps_calloc( size_t n, size_t size, uint32_t caps)
129 {
130     void *ptr = heap_caps_calloc_base(n, size, caps);
131 
132     if (!ptr && size > 0) {
133         heap_caps_alloc_failed(size, caps, __func__);
134     }
135 
136     return ptr;
137 }
138 
139 
heap_caps_calloc_prefer(size_t n,size_t size,size_t num,...)140 void *heap_caps_calloc_prefer( size_t n, size_t size, size_t num, ... )
141 {
142     return heap_caps_calloc_base(n, size, MALLOC_CAP_DEFAULT);
143 }
144 
heap_caps_get_total_size(uint32_t caps)145 size_t heap_caps_get_total_size(uint32_t caps)
146 {
147     return K_HEAP_MEM_POOL_SIZE;
148 }
149 
heap_caps_get_free_size(uint32_t caps)150 size_t heap_caps_get_free_size( uint32_t caps )
151 {
152     // Not implemented
153     return 0;
154 }
155 
heap_caps_get_minimum_free_size(uint32_t caps)156 size_t heap_caps_get_minimum_free_size( uint32_t caps )
157 {
158     // Not implemented
159     return 0;
160 }
161 
heap_caps_get_largest_free_block(uint32_t caps)162 size_t heap_caps_get_largest_free_block( uint32_t caps )
163 {
164     // Not implemented
165     return 0;
166 }
167 
heap_caps_get_info(multi_heap_info_t * info,uint32_t caps)168 void heap_caps_get_info( multi_heap_info_t *info, uint32_t caps )
169 {
170     memset(info, 0, sizeof(multi_heap_info_t));
171 }
172 
heap_caps_print_heap_info(uint32_t caps)173 void heap_caps_print_heap_info( uint32_t caps )
174 {
175     printf("No heap summary available when building for the zephyr target");
176 }
177 
heap_caps_check_integrity(uint32_t caps,bool print_errors)178 bool heap_caps_check_integrity(uint32_t caps, bool print_errors)
179 {
180     return true;
181 }
182 
heap_caps_check_integrity_all(bool print_errors)183 bool heap_caps_check_integrity_all(bool print_errors)
184 {
185     return heap_caps_check_integrity(MALLOC_CAP_INVALID, print_errors);
186 }
187 
heap_caps_check_integrity_addr(intptr_t addr,bool print_errors)188 bool heap_caps_check_integrity_addr(intptr_t addr, bool print_errors)
189 {
190     return true;
191 }
192 
heap_caps_dump(uint32_t caps)193 void heap_caps_dump(uint32_t caps)
194 {
195     // Not implemented
196 
197 }
198 
heap_caps_dump_all(void)199 void heap_caps_dump_all(void)
200 {
201     heap_caps_dump(MALLOC_CAP_INVALID);
202 }
203 
heap_caps_get_allocated_size(void * ptr)204 size_t heap_caps_get_allocated_size( void *ptr )
205 {
206     return 0;
207 }
208 
heap_caps_aligned_alloc(size_t alignment,size_t size,uint32_t caps)209 void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps)
210 {
211     void *ptr = k_aligned_alloc(alignment, size);
212 
213     if (!ptr && size > 0) {
214         heap_caps_alloc_failed(size, caps, __func__);
215     }
216 
217     return ptr;
218 }
219 
heap_caps_aligned_free(void * ptr)220 void heap_caps_aligned_free(void *ptr)
221 {
222     heap_caps_free(ptr);
223 }
224 
heap_caps_aligned_calloc(size_t alignment,size_t n,size_t size,uint32_t caps)225 void *heap_caps_aligned_calloc(size_t alignment, size_t n, size_t size, uint32_t caps)
226 {
227     size_t size_bytes;
228     if (__builtin_mul_overflow(n, size, &size_bytes)) {
229         return NULL;
230     }
231 
232     void *ptr = heap_caps_aligned_alloc(alignment, size_bytes, caps);
233     if (ptr != NULL) {
234         memset(ptr, 0, size_bytes);
235     }
236 
237     return ptr;
238 }
239