From a2db437c46ded825f5d702c047304867b0c39050 Mon Sep 17 00:00:00 2001 From: Felipe Neves Date: Wed, 13 Nov 2019 16:37:07 +0800 Subject: [PATCH] heap/heap_caps: Added tests for align allocation on both internal and external ram --- components/heap/heap_caps.c | 40 +++-------- components/heap/multi_heap_poisoning.c | 3 + .../heap/test/test_aligned_alloc_caps.c | 70 +++++++++++++++++++ 3 files changed, 83 insertions(+), 30 deletions(-) create mode 100644 components/heap/test/test_aligned_alloc_caps.c diff --git a/components/heap/heap_caps.c b/components/heap/heap_caps.c index 322ce23a89..9cbe08a9e4 100644 --- a/components/heap/heap_caps.c +++ b/components/heap/heap_caps.c @@ -522,23 +522,14 @@ IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, int caps) return NULL; } - if (caps & MALLOC_CAP_EXEC) { - //MALLOC_CAP_EXEC forces an alloc from IRAM. There is a region which has both this as well as the following - //caps, but the following caps are not possible for IRAM. Thus, the combination is impossible and we return - //NULL directly, even although our heap capabilities (based on soc_memory_tags & soc_memory_regions) would - //indicate there is a tag for this. - if ((caps & MALLOC_CAP_8BIT) || (caps & MALLOC_CAP_DMA)) { - return NULL; - } - caps |= MALLOC_CAP_32BIT; // IRAM is 32-bit accessible RAM + //aligned alloc for now only supports default allocator or external + //allocator. + if((caps & (MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM)) == 0) { + return NULL; } - if (caps & MALLOC_CAP_32BIT) { - /* 32-bit accessible RAM should allocated in 4 byte aligned sizes - * (Future versions of ESP-IDF should possibly fail if an invalid size is requested) - */ - size = (size + 3) & (~3); // int overflow checked above - } + //if caps requested are supported, clear undesired others: + caps &= (MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM); for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) { //Iterate over heaps and check capabilities at this priority @@ -551,21 +542,10 @@ IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, int caps) //Heap has at least one of the caps requested. If caps has other bits set that this prio //doesn't cover, see if they're available in other prios. if ((get_all_caps(heap) & caps) == caps) { - //This heap can satisfy all the requested capabilities. See if we can grab some memory using it. - if ((caps & MALLOC_CAP_EXEC) && esp_ptr_in_diram_dram((void *)heap->start)) { - //This is special, insofar that what we're going to get back is a DRAM address. If so, - //we need to 'invert' it (lowest address in DRAM == highest address in IRAM and vice-versa) and - //add a pointer to the DRAM equivalent before the address we're going to return. - ret = multi_heap_aligned_alloc(heap->heap, size + 4, alignment); // int overflow checked above - if (ret != NULL) { - return dram_alloc_to_iram_addr(ret, size + 4); // int overflow checked above - } - } else { - //Just try to alloc, nothing special. - ret = multi_heap_aligned_alloc(heap->heap, size, alignment); - if (ret != NULL) { - return ret; - } + //Just try to alloc, nothing special. + ret = multi_heap_aligned_alloc(heap->heap, size, alignment); + if (ret != NULL) { + return ret; } } } diff --git a/components/heap/multi_heap_poisoning.c b/components/heap/multi_heap_poisoning.c index 906c827d47..8a356e6495 100644 --- a/components/heap/multi_heap_poisoning.c +++ b/components/heap/multi_heap_poisoning.c @@ -222,6 +222,9 @@ void *multi_heap_aligned_alloc(multi_heap_handle_t heap, size_t size, size_t ali #else (void)data; #endif + } else { + multi_heap_internal_unlock(heap); + return NULL; } //Lets align our new obtained block address: diff --git a/components/heap/test/test_aligned_alloc_caps.c b/components/heap/test/test_aligned_alloc_caps.c new file mode 100644 index 0000000000..909e654e79 --- /dev/null +++ b/components/heap/test/test_aligned_alloc_caps.c @@ -0,0 +1,70 @@ +/* + Tests for the capabilities-based memory allocator. +*/ + +#include +#include +#include "unity.h" +#include "esp_attr.h" +#include "esp_heap_caps.h" +#include "esp_spi_flash.h" +#include +#include +#include + +TEST_CASE("Capabilities aligned allocator test", "[heap]") +{ + uint32_t alignments = 0; + + printf("[ALIGNED_ALLOC] Allocating from default CAP: \n"); + + for(;alignments <= 1024; alignments++) { + uint8_t *buf = (uint8_t *)heap_caps_aligned_alloc(alignments, (alignments + 137), MALLOC_CAP_DEFAULT); + if(((alignments & (alignments - 1)) != 0) || (!alignments)) { + TEST_ASSERT( buf == NULL ); + //printf("[ALIGNED_ALLOC] alignment: %u is not a power of two, don't allow allocation \n", aligments); + } else { + TEST_ASSERT( buf != NULL ); + printf("[ALIGNED_ALLOC] alignment required: %u \n", alignments); + printf("[ALIGNED_ALLOC] address of allocated memory: %p \n\n", (void *)buf); + //Address of obtained block must be aligned with selected value + TEST_ASSERT(((intptr_t)buf & (alignments - 1)) == 0); + + //Write some data, if it corrupts memory probably the heap + //canary verification will fail: + memset(buf, 0xA5, (alignments + 137)); + + heap_caps_aligned_free(buf); + } + } + + //Alloc from a non permitted area: + uint32_t *not_permitted_buf = (uint32_t *)heap_caps_aligned_alloc(alignments, (alignments + 137), MALLOC_CAP_EXEC | MALLOC_CAP_32BIT); + TEST_ASSERT( not_permitted_buf == NULL ); + +#if CONFIG_ESP32_SPIRAM_SUPPORT || CONFIG_ESP32S2_SPIRAM_SUPPORT + alignments = 0; + printf("[ALIGNED_ALLOC] Allocating from external memory: \n"); + + for(;alignments <= 1024 * 1024; alignments++) { + //Now try to take aligned memory from IRAM: + uint8_t *buf = (uint8_t *)heap_caps_aligned_alloc(alignments, 10*1024, MALLOC_CAP_SPIRAM); + if(((alignments & (alignments - 1)) != 0) || (!alignments)) { + TEST_ASSERT( buf == NULL ); + //printf("[ALIGNED_ALLOC] alignment: %u is not a power of two, don't allow allocation \n", aligments); + } else { + TEST_ASSERT( buf != NULL ); + printf("[ALIGNED_ALLOC] alignment required: %u \n", alignments); + printf("[ALIGNED_ALLOC] address of allocated memory: %p \n\n", (void *)buf); + //Address of obtained block must be aligned with selected value + TEST_ASSERT(((intptr_t)buf & (alignments - 1)) == 0); + + //Write some data, if it corrupts memory probably the heap + //canary verification will fail: + memset(buf, 0xA5, (10*1024)); + heap_caps_aligned_free(buf); + } + } +#endif + +} \ No newline at end of file