123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609 |
- #include <stdbool.h>
- #include <string.h>
- #include <assert.h>
- #include <stdio.h>
- #include <sys/param.h>
- #include "esp_attr.h"
- #include "esp_heap_caps.h"
- #include "multi_heap.h"
- #include "esp_log.h"
- #include "heap_private.h"
- #include "esp_system.h"
- static esp_alloc_failed_hook_t alloc_failed_callback;
- IRAM_ATTR static void *dram_alloc_to_iram_addr(void *addr, size_t len)
- {
- uintptr_t dstart = (uintptr_t)addr;
- uintptr_t dend = dstart + len - 4;
- assert(esp_ptr_in_diram_dram((void *)dstart));
- assert(esp_ptr_in_diram_dram((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 = esp_ptr_diram_dram_to_iram((void *)dstart);
- #endif
- *iptr = dstart;
- return iptr + 1;
- }
- static void heap_caps_alloc_failed(size_t requested_size, uint32_t caps, const char *function_name)
- {
- if (alloc_failed_callback) {
- alloc_failed_callback(requested_size, caps, function_name);
- }
- #ifdef CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS
- esp_system_abort("Memory allocation failed");
- #endif
- }
- esp_err_t heap_caps_register_failed_alloc_callback(esp_alloc_failed_hook_t callback)
- {
- if (callback == NULL) {
- return ESP_ERR_INVALID_ARG;
- }
- alloc_failed_callback = callback;
- return ESP_OK;
- }
- bool heap_caps_match(const heap_t *heap, uint32_t caps)
- {
- return heap->heap != NULL && ((get_all_caps(heap) & caps) == caps);
- }
- IRAM_ATTR void *heap_caps_malloc( size_t size, uint32_t caps )
- {
- void *ret = NULL;
- if (size > HEAP_SIZE_MAX) {
-
-
- heap_caps_alloc_failed(size, caps, __func__);
- return NULL;
- }
- if (caps & MALLOC_CAP_EXEC) {
-
-
-
-
- if ((caps & MALLOC_CAP_8BIT) || (caps & MALLOC_CAP_DMA)) {
- heap_caps_alloc_failed(size, caps, __func__);
- 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_ptr_in_diram_dram((void *)heap->start)) {
-
-
-
- ret = multi_heap_malloc(heap->heap, size + 4);
- if (ret != NULL) {
- return dram_alloc_to_iram_addr(ret, size + 4);
- }
- } else {
-
- ret = multi_heap_malloc(heap->heap, size);
- if (ret != NULL) {
- return ret;
- }
- }
- }
- }
- }
- }
- heap_caps_alloc_failed(size, caps, __func__);
-
- return NULL;
- }
- #define MALLOC_DISABLE_EXTERNAL_ALLOCS -1
- static int malloc_alwaysinternal_limit=MALLOC_DISABLE_EXTERNAL_ALLOCS;
- void heap_caps_malloc_extmem_enable(size_t limit)
- {
- malloc_alwaysinternal_limit=limit;
- }
- IRAM_ATTR void *heap_caps_malloc_default( size_t size )
- {
- if (malloc_alwaysinternal_limit==MALLOC_DISABLE_EXTERNAL_ALLOCS) {
- return heap_caps_malloc( size, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
- } else {
- void *r;
- if (size <= (size_t)malloc_alwaysinternal_limit) {
- r=heap_caps_malloc( size, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL );
- } else {
- r=heap_caps_malloc( size, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM );
- }
- if (r==NULL) {
-
- r=heap_caps_malloc( size, MALLOC_CAP_DEFAULT );
- }
- return r;
- }
- }
- IRAM_ATTR void *heap_caps_realloc_default( void *ptr, size_t size )
- {
- if (malloc_alwaysinternal_limit==MALLOC_DISABLE_EXTERNAL_ALLOCS) {
- return heap_caps_realloc( ptr, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL );
- } else {
- void *r;
- if (size <= (size_t)malloc_alwaysinternal_limit) {
- r=heap_caps_realloc( ptr, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL );
- } else {
- r=heap_caps_realloc( ptr, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM );
- }
- if (r==NULL && size>0) {
-
- r=heap_caps_realloc( ptr, size, MALLOC_CAP_DEFAULT );
- }
- return r;
- }
- }
- IRAM_ATTR void *heap_caps_malloc_prefer( size_t size, size_t num, ... )
- {
- va_list argp;
- va_start( argp, num );
- void *r = NULL;
- while (num--) {
- uint32_t caps = va_arg( argp, uint32_t );
- r = heap_caps_malloc( size, caps );
- if (r != NULL) {
- break;
- }
- }
- va_end( argp );
- return r;
- }
- IRAM_ATTR void *heap_caps_realloc_prefer( void *ptr, size_t size, size_t num, ... )
- {
- va_list argp;
- va_start( argp, num );
- void *r = NULL;
- while (num--) {
- uint32_t caps = va_arg( argp, uint32_t );
- r = heap_caps_realloc( ptr, size, caps );
- if (r != NULL || size == 0) {
- break;
- }
- }
- va_end( argp );
- return r;
- }
- IRAM_ATTR void *heap_caps_calloc_prefer( size_t n, size_t size, size_t num, ... )
- {
- va_list argp;
- va_start( argp, num );
- void *r = NULL;
- while (num--) {
- uint32_t caps = va_arg( argp, uint32_t );
- r = heap_caps_calloc( n, size, caps );
- if (r != NULL) break;
- }
- va_end( argp );
- return r;
- }
- IRAM_ATTR static heap_t *find_containing_heap(void *ptr )
- {
- intptr_t p = (intptr_t)ptr;
- heap_t *heap;
- SLIST_FOREACH(heap, ®istered_heaps, next) {
- if (heap->heap != NULL && p >= heap->start && p < heap->end) {
- return heap;
- }
- }
- return NULL;
- }
- IRAM_ATTR void heap_caps_free( void *ptr)
- {
- if (ptr == NULL) {
- return;
- }
- if (esp_ptr_in_diram_iram(ptr)) {
-
-
-
- uint32_t *dramAddrPtr = (uint32_t *)ptr;
- ptr = (void *)dramAddrPtr[-1];
- }
- heap_t *heap = find_containing_heap(ptr);
- assert(heap != NULL && "free() target pointer is outside heap areas");
- multi_heap_free(heap->heap, ptr);
- }
- IRAM_ATTR void *heap_caps_realloc( void *ptr, size_t size, uint32_t caps)
- {
- bool ptr_in_diram_case = false;
- heap_t *heap = NULL;
- void *dram_ptr = NULL;
- if (ptr == NULL) {
- return heap_caps_malloc(size, caps);
- }
- if (size == 0) {
- heap_caps_free(ptr);
- return NULL;
- }
- if (size > HEAP_SIZE_MAX) {
- heap_caps_alloc_failed(size, caps, __func__);
- return NULL;
- }
-
-
- if(esp_ptr_in_diram_iram((void *)ptr)) {
- uint32_t *dram_addr = (uint32_t *)ptr;
- dram_ptr = (void *)dram_addr[-1];
- 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");
- }
-
-
- bool compatible_caps = (caps & get_all_caps(heap)) == caps;
- if (compatible_caps && !ptr_in_diram_case) {
-
-
- void *r = multi_heap_realloc(heap->heap, ptr, size);
- if (r != NULL) {
- return r;
- }
- }
-
-
- void *new_p = heap_caps_malloc(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, ptr, MIN(size, old_size));
- heap_caps_free(ptr);
- return new_p;
- }
- heap_caps_alloc_failed(size, caps, __func__);
- return NULL;
- }
- IRAM_ATTR void *heap_caps_calloc( 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(size_bytes, caps);
- if (result != NULL) {
- bzero(result, size_bytes);
- }
- return result;
- }
- size_t heap_caps_get_total_size(uint32_t caps)
- {
- size_t total_size = 0;
- heap_t *heap;
- SLIST_FOREACH(heap, ®istered_heaps, next) {
- if (heap_caps_match(heap, caps)) {
- total_size += (heap->end - heap->start);
- }
- }
- return total_size;
- }
- size_t heap_caps_get_free_size( uint32_t caps )
- {
- size_t ret = 0;
- heap_t *heap;
- SLIST_FOREACH(heap, ®istered_heaps, next) {
- if (heap_caps_match(heap, caps)) {
- ret += multi_heap_free_size(heap->heap);
- }
- }
- return ret;
- }
- size_t heap_caps_get_minimum_free_size( uint32_t caps )
- {
- size_t ret = 0;
- heap_t *heap;
- SLIST_FOREACH(heap, ®istered_heaps, next) {
- if (heap_caps_match(heap, caps)) {
- ret += multi_heap_minimum_free_size(heap->heap);
- }
- }
- return ret;
- }
- size_t heap_caps_get_largest_free_block( uint32_t caps )
- {
- multi_heap_info_t info;
- heap_caps_get_info(&info, caps);
- return info.largest_free_block;
- }
- void heap_caps_get_info( multi_heap_info_t *info, uint32_t caps )
- {
- bzero(info, sizeof(multi_heap_info_t));
- heap_t *heap;
- SLIST_FOREACH(heap, ®istered_heaps, next) {
- if (heap_caps_match(heap, caps)) {
- multi_heap_info_t hinfo;
- multi_heap_get_info(heap->heap, &hinfo);
- info->total_free_bytes += hinfo.total_free_bytes;
- info->total_allocated_bytes += hinfo.total_allocated_bytes;
- info->largest_free_block = MAX(info->largest_free_block,
- hinfo.largest_free_block);
- info->minimum_free_bytes += hinfo.minimum_free_bytes;
- info->allocated_blocks += hinfo.allocated_blocks;
- info->free_blocks += hinfo.free_blocks;
- info->total_blocks += hinfo.total_blocks;
- }
- }
- }
- void heap_caps_print_heap_info( uint32_t caps )
- {
- multi_heap_info_t info;
- printf("Heap summary for capabilities 0x%08X:\n", caps);
- heap_t *heap;
- SLIST_FOREACH(heap, ®istered_heaps, next) {
- if (heap_caps_match(heap, caps)) {
- multi_heap_get_info(heap->heap, &info);
- printf(" At 0x%08x len %d free %d allocated %d min_free %d\n",
- heap->start, heap->end - heap->start, info.total_free_bytes, info.total_allocated_bytes, info.minimum_free_bytes);
- printf(" largest_free_block %d alloc_blocks %d free_blocks %d total_blocks %d\n",
- info.largest_free_block, info.allocated_blocks,
- info.free_blocks, info.total_blocks);
- }
- }
- printf(" Totals:\n");
- heap_caps_get_info(&info, caps);
- printf(" free %d allocated %d min_free %d largest_free_block %d\n", info.total_free_bytes, info.total_allocated_bytes, info.minimum_free_bytes, info.largest_free_block);
- }
- bool heap_caps_check_integrity(uint32_t caps, bool print_errors)
- {
- bool all_heaps = caps & MALLOC_CAP_INVALID;
- bool valid = true;
- heap_t *heap;
- SLIST_FOREACH(heap, ®istered_heaps, next) {
- if (heap->heap != NULL
- && (all_heaps || (get_all_caps(heap) & caps) == caps)) {
- valid = multi_heap_check(heap->heap, print_errors) && valid;
- }
- }
- return valid;
- }
- bool heap_caps_check_integrity_all(bool print_errors)
- {
- return heap_caps_check_integrity(MALLOC_CAP_INVALID, print_errors);
- }
- bool heap_caps_check_integrity_addr(intptr_t addr, bool print_errors)
- {
- heap_t *heap = find_containing_heap((void *)addr);
- if (heap == NULL) {
- return false;
- }
- return multi_heap_check(heap->heap, print_errors);
- }
- void heap_caps_dump(uint32_t caps)
- {
- bool all_heaps = caps & MALLOC_CAP_INVALID;
- heap_t *heap;
- SLIST_FOREACH(heap, ®istered_heaps, next) {
- if (heap->heap != NULL
- && (all_heaps || (get_all_caps(heap) & caps) == caps)) {
- multi_heap_dump(heap->heap);
- }
- }
- }
- void heap_caps_dump_all(void)
- {
- heap_caps_dump(MALLOC_CAP_INVALID);
- }
- size_t heap_caps_get_allocated_size( void *ptr )
- {
- heap_t *heap = find_containing_heap(ptr);
- size_t size = multi_heap_get_allocated_size(heap->heap, ptr);
- return size;
- }
- IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps)
- {
- void *ret = NULL;
- if(!alignment) {
- return NULL;
- }
-
- if((alignment & (alignment - 1)) != 0) {
- return NULL;
- }
- if (size > HEAP_SIZE_MAX) {
-
-
- heap_caps_alloc_failed(size, caps, __func__);
- return NULL;
- }
- 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) {
-
- ret = multi_heap_aligned_alloc(heap->heap, size, alignment);
- if (ret != NULL) {
- return ret;
- }
- }
- }
- }
- }
- heap_caps_alloc_failed(size, caps, __func__);
-
- return NULL;
- }
- IRAM_ATTR void heap_caps_aligned_free(void *ptr)
- {
- heap_caps_free(ptr);
- }
- void *heap_caps_aligned_calloc(size_t alignment, size_t n, size_t size, uint32_t caps)
- {
- size_t size_bytes;
- if (__builtin_mul_overflow(n, size, &size_bytes)) {
- return NULL;
- }
- void *ptr = heap_caps_aligned_alloc(alignment,size_bytes, caps);
- if(ptr != NULL) {
- memset(ptr, 0, size_bytes);
- }
- return ptr;
- }
|