1
6
15
16
17
23
24
25
26
27
28
29
30
31
32
37
38
39
40
41
42
43
44
45
46
47
48
55
56
57
58
59
60
61
64
65
72
73
74
75
76
77
78
79
80
87
88
93
94
95
96
97
98
99
100
101
102
107
108
109
110
111
112
113
116
117
118
119
125
126
127
128
129
130
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
154
165
166
167
168
169
170
171
172
173
174
175
178
179
183
184
185
186
187
188
189
190
191
192
193
196
197
201
202
203
204
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
227
228
229
230
231
232
233
234
235
236
237
238
239
240
251
252
253
254
255
256
257
258
259
260
265
266
267
268
269
270
271
272
273
274
275
276
277
281
282
283
284
285
286
289
290
291
294
295
/* ... */
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <sys/param.h>
#include "esp_attr.h"
#include "multi_heap.h"
#include "esp_log.h"
#include "heap_private.h"9 includes
#ifdef CONFIG_HEAP_USE_HOOKS
#define CALL_HOOK(hook, ...) { \
if (hook != NULL) { \
hook(__VA_ARGS__); \
}{...} \
}{...}
/* ... */#else
#define CALL_HOOK(hook, ...) {}
#endif
extern void esp_heap_adjust_alignment_to_hw(size_t *p_alignment, size_t *p_size, uint32_t *p_caps);
#define UNALIGNED_MEM_ALIGNMENT_BYTES 4
/* ... */
HEAP_IRAM_ATTR static void *dram_alloc_to_iram_addr(void *addr, size_t len)
{
uintptr_t dstart = (uintptr_t)addr;
uintptr_t dend __attribute__((unused)) = dstart + len - 4;
assert(esp_ptr_in_diram_dram((void *)dstart) || esp_ptr_in_rtc_dram_fast((void *)dstart));
assert(esp_ptr_in_diram_dram((void *)dend) || esp_ptr_in_rtc_dram_fast((void *)dend));
assert((dstart & 3) == 0);
assert((dend & 3) == 0);
#if SOC_DIRAM_INVERTED
uint32_t *iptr = esp_ptr_diram_dram_to_iram((void *)dend);
#else
uint32_t *iptr = NULL;
if (esp_ptr_in_rtc_dram_fast((void *)dstart)) {
iptr = esp_ptr_rtc_dram_to_iram((void *)dstart);
}{...} else {
iptr = esp_ptr_diram_dram_to_iram((void *)dstart);
}{...}
#endif/* ... */
*iptr = dstart;
return iptr + 1;
}{ ... }
HEAP_IRAM_ATTR void heap_caps_free( void *ptr)
{
if (ptr == NULL) {
return;
}{...}
if (esp_ptr_in_diram_iram(ptr) || esp_ptr_in_rtc_iram_fast(ptr)) {
uint32_t *dramAddrPtr = (uint32_t *)ptr;
ptr = (void *)dramAddrPtr[-1];
}{...}
void *block_owner_ptr = MULTI_HEAP_REMOVE_BLOCK_OWNER_OFFSET(ptr);
heap_t *heap = find_containing_heap(block_owner_ptr);
assert(heap != NULL && "free() target pointer is outside heap areas");
multi_heap_free(heap->heap, block_owner_ptr);
CALL_HOOK(esp_heap_trace_free_hook, ptr);
}{ ... }
HEAP_IRAM_ATTR static inline void *aligned_or_unaligned_alloc(multi_heap_handle_t heap, size_t size, size_t alignment, size_t offset) {
if (alignment<=UNALIGNED_MEM_ALIGNMENT_BYTES) {
return multi_heap_malloc(heap, size);
}{...} else {
return multi_heap_aligned_alloc_offs(heap, size, alignment, offset);
}{...}
}{ ... }
/* ... */
HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_aligned_alloc_base(size_t alignment, size_t size, uint32_t caps)
{
void *ret = NULL;
esp_heap_adjust_alignment_to_hw(&alignment, &size, &caps);
if (size == 0 || size > MULTI_HEAP_REMOVE_BLOCK_OWNER_SIZE(HEAP_SIZE_MAX) ) {
return NULL;
}{...}
if (caps & MALLOC_CAP_EXEC) {
if ((caps & MALLOC_CAP_8BIT) || (caps & MALLOC_CAP_DMA)) {
return NULL;
}{...}
caps |= MALLOC_CAP_32BIT;
}{...}
if (caps & MALLOC_CAP_32BIT) {
/* ... */
size = (size + 3) & (~3);
}{...}
for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) {
heap_t *heap;
SLIST_FOREACH(heap, ®istered_heaps, next) {
if (heap->heap == NULL) {
continue;
}{...}
if ((heap->caps[prio] & caps) != 0) {
if ((get_all_caps(heap) & caps) == caps) {
if (((caps & MALLOC_CAP_EXEC) && !esp_dram_match_iram()) &&
(esp_ptr_in_diram_dram((void *)heap->start) || esp_ptr_in_rtc_dram_fast((void *)heap->start))) {
ret = aligned_or_unaligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size) + 4,
alignment, MULTI_HEAP_BLOCK_OWNER_SIZE());
if (ret != NULL) {
MULTI_HEAP_SET_BLOCK_OWNER(ret);
ret = MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ret);
uint32_t *iptr = dram_alloc_to_iram_addr(ret, size + 4);
CALL_HOOK(esp_heap_trace_alloc_hook, iptr, size, caps);
return iptr;
}{...}
}{...} else {
ret = aligned_or_unaligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size),
alignment, MULTI_HEAP_BLOCK_OWNER_SIZE());
if (ret != NULL) {
MULTI_HEAP_SET_BLOCK_OWNER(ret);
ret = MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ret);
CALL_HOOK(esp_heap_trace_alloc_hook, ret, size, caps);
return ret;
}{...}
}{...}
}{...}
}{...}
}{...}
}{...}
return NULL;
}{ ... }
HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_malloc_base( size_t size, uint32_t caps) {
return heap_caps_aligned_alloc_base(UNALIGNED_MEM_ALIGNMENT_BYTES, size, caps);
}{ ... }
/* ... */
HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_realloc_base( void *ptr, size_t size, uint32_t caps)
{
bool ptr_in_diram_case = false;
heap_t *heap = NULL;
void *dram_ptr = NULL;
size_t alignment = UNALIGNED_MEM_ALIGNMENT_BYTES;
esp_heap_adjust_alignment_to_hw(&alignment, &size, &caps);
if (ptr == NULL) {
return heap_caps_aligned_alloc_base(alignment, size, caps);
}{...}
if (size == 0) {
heap_caps_free(ptr);
return NULL;
}{...}
if (size > MULTI_HEAP_REMOVE_BLOCK_OWNER_SIZE(HEAP_SIZE_MAX)) {
return NULL;
}{...}
if(esp_ptr_in_diram_iram((void *)ptr)) {
uint32_t *dram_addr = (uint32_t *)ptr;
dram_ptr = (void *)dram_addr[-1];
dram_ptr = MULTI_HEAP_REMOVE_BLOCK_OWNER_OFFSET(dram_ptr);
heap = find_containing_heap(dram_ptr);
assert(heap != NULL && "realloc() pointer is outside heap areas");
ptr_in_diram_case = true;
}{...} else {
heap = find_containing_heap(ptr);
assert(heap != NULL && "realloc() pointer is outside heap areas");
}{...}
ptr = MULTI_HEAP_REMOVE_BLOCK_OWNER_OFFSET(ptr);
bool compatible_caps = (caps & get_all_caps(heap)) == caps;
if (compatible_caps && !ptr_in_diram_case && alignment<=UNALIGNED_MEM_ALIGNMENT_BYTES) {
void *r = multi_heap_realloc(heap->heap, ptr, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size));
if (r != NULL) {
MULTI_HEAP_SET_BLOCK_OWNER(r);
r = MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(r);
CALL_HOOK(esp_heap_trace_alloc_hook, r, size, caps);
return r;
}{...}
}{...}
void *new_p = heap_caps_aligned_alloc_base(alignment, size, caps);
if (new_p != NULL) {
size_t old_size = 0;
if(ptr_in_diram_case) {
old_size = multi_heap_get_allocated_size(heap->heap, dram_ptr);
}{...} else {
old_size = multi_heap_get_allocated_size(heap->heap, ptr);
}{...}
assert(old_size > 0);
memcpy(new_p, MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ptr), MIN(size, old_size));
heap_caps_free(MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ptr));
return new_p;
}{...}
return NULL;
}{ ... }
/* ... */
HEAP_IRAM_ATTR void *heap_caps_calloc_base( size_t n, size_t size, uint32_t caps)
{
void *result;
size_t size_bytes;
if (__builtin_mul_overflow(n, size, &size_bytes)) {
return NULL;
}{...}
result = heap_caps_malloc_base(size_bytes, caps);
if (result != NULL) {
memset(result, 0, size_bytes);
}{...}
return result;
}{ ... }