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