diff --git a/components/heap/heap_caps.c b/components/heap/heap_caps.c index 501ebe6392..73ac52d85c 100644 --- a/components/heap/heap_caps.c +++ b/components/heap/heap_caps.c @@ -660,31 +660,8 @@ size_t heap_caps_get_allocated_size( void *ptr ) return MULTI_HEAP_REMOVE_BLOCK_OWNER_SIZE(size); } -HEAP_IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps) +static HEAP_IRAM_ATTR void *heap_caps_aligned_alloc_base(size_t alignment, size_t size, uint32_t caps) { - void *ret = NULL; - - if(!alignment) { - return NULL; - } - - //Alignment must be a power of two: - if((alignment & (alignment - 1)) != 0) { - return NULL; - } - - if (size == 0) { - return NULL; - } - - if (MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size) > HEAP_SIZE_MAX) { - // Avoids int overflow when adding small numbers to size, or - // calculating 'end' from start+size, by limiting 'size' to the possible range - heap_caps_alloc_failed(size, caps, __func__); - - return NULL; - } - for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) { //Iterate over heaps and check capabilities at this priority heap_t *heap; @@ -697,7 +674,7 @@ HEAP_IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint //doesn't cover, see if they're available in other prios. if ((get_all_caps(heap) & caps) == caps) { //Just try to alloc, nothing special. - ret = multi_heap_aligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size), alignment); + void *ret = multi_heap_aligned_alloc(heap->heap, MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size), alignment); if (ret != NULL) { MULTI_HEAP_SET_BLOCK_OWNER(ret); ret = MULTI_HEAP_ADD_BLOCK_OWNER_OFFSET(ret); @@ -709,12 +686,83 @@ HEAP_IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint } } - heap_caps_alloc_failed(size, caps, __func__); - //Nothing usable found. return NULL; } +static HEAP_IRAM_ATTR esp_err_t heap_caps_aligned_check_args(size_t alignment, size_t size, uint32_t caps, const char *funcname) +{ + if (!alignment) { + return ESP_FAIL; + } + + // Alignment must be a power of two: + if ((alignment & (alignment - 1)) != 0) { + return ESP_FAIL; + } + + if (size == 0) { + return ESP_FAIL; + } + + if (MULTI_HEAP_ADD_BLOCK_OWNER_SIZE(size) > HEAP_SIZE_MAX) { + // Avoids int overflow when adding small numbers to size, or + // calculating 'end' from start+size, by limiting 'size' to the possible range + heap_caps_alloc_failed(size, caps, funcname); + return ESP_FAIL; + } + + return ESP_OK; +} + +HEAP_IRAM_ATTR void *heap_caps_aligned_alloc_default(size_t alignment, size_t size) +{ + void *ret = NULL; + + if (malloc_alwaysinternal_limit == MALLOC_DISABLE_EXTERNAL_ALLOCS) { + return heap_caps_aligned_alloc(alignment, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); + } + + if (heap_caps_aligned_check_args(alignment, size, MALLOC_CAP_DEFAULT, __func__) != ESP_OK) { + return NULL; + } + + if (size <= (size_t)malloc_alwaysinternal_limit) { + ret = heap_caps_aligned_alloc_base(alignment, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL); + } else { + ret = heap_caps_aligned_alloc_base(alignment, size, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM); + } + + if (ret != NULL) { + return ret; + } + + ret = heap_caps_aligned_alloc_base(alignment, size, MALLOC_CAP_DEFAULT); + + if (ret == NULL) { + heap_caps_alloc_failed(size, MALLOC_CAP_DEFAULT, __func__); + } + + return ret; +} + +HEAP_IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t caps) +{ + void *ret = NULL; + + if (heap_caps_aligned_check_args(alignment, size, caps, __func__) != ESP_OK) { + return NULL; + } + + ret = heap_caps_aligned_alloc_base(alignment, size, caps); + + if (ret == NULL) { + heap_caps_alloc_failed(size, caps, __func__); + } + + return ret; +} + HEAP_IRAM_ATTR void heap_caps_aligned_free(void *ptr) { heap_caps_free(ptr); diff --git a/components/heap/heap_private.h b/components/heap/heap_private.h index 51b6773ffa..fde7a78bcf 100644 --- a/components/heap/heap_private.h +++ b/components/heap/heap_private.h @@ -62,6 +62,7 @@ inline static uint32_t get_all_caps(const heap_t *heap) */ void *heap_caps_realloc_default(void *p, size_t size); void *heap_caps_malloc_default(size_t size); +void *heap_caps_aligned_alloc_default(size_t alignment, size_t size); #ifdef __cplusplus diff --git a/components/newlib/heap.c b/components/newlib/heap.c index fca44906a2..685e1e3c72 100644 --- a/components/newlib/heap.c +++ b/components/newlib/heap.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ */ extern void *heap_caps_malloc_default( size_t size ); extern void *heap_caps_realloc_default( void *ptr, size_t size ); +extern void *heap_caps_aligned_alloc_default( size_t alignment, size_t size ); void* malloc(size_t size) { @@ -71,7 +72,7 @@ void* _calloc_r(struct _reent *r, size_t nmemb, size_t size) void* memalign(size_t alignment, size_t n) { - return heap_caps_aligned_alloc(alignment, n, MALLOC_CAP_DEFAULT); + return heap_caps_aligned_alloc_default(alignment, n); } int posix_memalign(void **out_ptr, size_t alignment, size_t size) @@ -81,7 +82,7 @@ int posix_memalign(void **out_ptr, size_t alignment, size_t size) *out_ptr = NULL; return 0; } - void *result = heap_caps_aligned_alloc(alignment, size, MALLOC_CAP_DEFAULT); + void *result = heap_caps_aligned_alloc_default(alignment, size); if (result != NULL) { /* Modify output pointer only on success */ *out_ptr = result; diff --git a/components/newlib/test_apps/newlib/main/test_misc.c b/components/newlib/test_apps/newlib/main/test_misc.c index 98fe6dcae3..ec8a69b3f9 100644 --- a/components/newlib/test_apps/newlib/main/test_misc.c +++ b/components/newlib/test_apps/newlib/main/test_misc.c @@ -13,6 +13,7 @@ #include #include #include "unity.h" +#include "esp_heap_caps.h" TEST_CASE("misc - posix_memalign", "[newlib_misc]") @@ -41,6 +42,26 @@ TEST_CASE("misc - posix_memalign", "[newlib_misc]") TEST_ASSERT_NOT_NULL(outptr); TEST_ASSERT_EQUAL_INT(ret, 0); free(outptr); + + outptr = magic; + heap_caps_malloc_extmem_enable(128); + ret = posix_memalign(&outptr, 16, 64); + TEST_ASSERT_TRUE(outptr != magic); + TEST_ASSERT_NOT_NULL(outptr); + TEST_ASSERT_EQUAL_INT(ret, 0); + free(outptr); + + outptr = magic; + heap_caps_malloc_extmem_enable(64); + ret = posix_memalign(&outptr, 16, 128); + TEST_ASSERT_TRUE(outptr != magic); + TEST_ASSERT_NOT_NULL(outptr); + TEST_ASSERT_EQUAL_INT(ret, 0); + free(outptr); + +#if CONFIG_SPIRAM_USE_MALLOC + heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); +#endif } TEST_CASE("misc - sysconf", "[newlib_misc]")