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