heap/heap_caps: added initial, top level heap_caps_aligned_alloc and heap_caps_aligned_free

This commit is contained in:
Felipe Neves 2019-11-13 12:49:57 +08:00
parent f31b8a8ab8
commit 7fbf4c74d7
2 changed files with 115 additions and 0 deletions

View file

@ -502,3 +502,94 @@ size_t heap_caps_get_allocated_size( void *ptr )
size_t size = multi_heap_get_allocated_size(heap->heap, ptr); size_t size = multi_heap_get_allocated_size(heap->heap, ptr);
return size; return size;
} }
IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, int caps)
{
void *ret = NULL;
if(!alignment) {
return NULL;
}
//Alignment must be a power of two:
if((alignment & (alignment - 1)) != 0) {
return NULL;
}
if (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
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
}
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
}
for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) {
//Iterate over heaps and check capabilities at this priority
heap_t *heap;
SLIST_FOREACH(heap, &registered_heaps, next) {
if (heap->heap == NULL) {
continue;
}
if ((heap->caps[prio] & caps) != 0) {
//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;
}
}
}
}
}
}
//Nothing usable found.
return NULL;
}
IRAM_ATTR void heap_caps_aligned_free(void *ptr)
{
if (ptr == NULL) {
return;
}
if (esp_ptr_in_diram_iram(ptr)) {
//Memory allocated here is actually allocated in the DRAM alias region and
//cannot be de-allocated as usual. dram_alloc_to_iram_addr stores a pointer to
//the equivalent DRAM address, though; free that.
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_aligned_free(heap->heap, ptr);
}

View file

@ -85,6 +85,30 @@ void heap_caps_free( void *ptr);
*/ */
void *heap_caps_realloc( void *ptr, size_t size, int caps); void *heap_caps_realloc( void *ptr, size_t size, int caps);
/**
* @brief Allocate a aligned chunk of memory which has the given capabilities
*
* Equivalent semantics to libc aligned_alloc(), for capability-aware memory.
* @param alignment How the pointer received needs to be aligned
* must be a power of two
* @param size Size, in bytes, of the amount of memory to allocate
* @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type
* of memory to be returned
*
* @return A pointer to the memory allocated on success, NULL on failure
*/
void *heap_caps_aligned_alloc(size_t alignment, size_t size, int caps);
/**
* @brief Used to deallocate memory previously allocated with heap_caps_aligned_alloc
*
* @param ptr Pointer to the memory allocated
* @note This function is aimed to deallocate only memory allocated with
* heap_caps_aligned_alloc, memory allocated with heap_caps_malloc
* MUST not be passed to this function
*/
void heap_caps_aligned_free(void *ptr);
/** /**
* @brief Allocate a chunk of memory which has the given capabilities. The initialized value in the memory is set to zero. * @brief Allocate a chunk of memory which has the given capabilities. The initialized value in the memory is set to zero.
* *