From 25e7f3a303fb50ab1fa865c1a1b55dd05dbdca58 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Fri, 9 Dec 2016 15:48:32 +0800 Subject: [PATCH 1/7] Add name to tag type --- components/esp32/heap_alloc_caps.c | 53 ++++++++++++++++-------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 04e2dc8c8..3ec70c9d7 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -35,28 +35,33 @@ hardwiring addresses. //Amount of priority slots for the tag descriptors. #define NO_PRIOS 3 +typedef struct { + const char *name; + uint32_t prio[NO_PRIOS]; +} tag_desc_t; + /* Tag descriptors. These describe the capabilities of a bit of memory that's tagged with the index into this table. Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request. */ -static const uint32_t tagDesc[][NO_PRIOS]={ - { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, //Tag 0: Plain ole D-port RAM - { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, //Tag 1: Plain ole D-port RAM which has an alias on the I-port - { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }, //Tag 2: IRAM - { MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, //Tag 3-8: PID 2-7 IRAM - { MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, //Tag 9-14: PID 2-7 DRAM - { MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, // - { MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, //Tag 15: SPI SRAM data - { MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID } //End +static const tag_desc_t tag_desc[]={ + { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }}, //Tag 0: Plain ole D-port RAM + { "D/IRAM", { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }}, //Tag 1: Plain ole D-port RAM which has an alias on the I-port + { "IRAM", { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }}, //Tag 2: IRAM + { "PID2IRAM", { MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, //Tag 3-8: PID 2-7 IRAM + { "PID3IRAM", { MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // + { "PID4IRAM", { MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // + { "PID5IRAM", { MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // + { "PID6IRAM", { MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // + { "PID7IRAM", { MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // + { "PID2DRAM", { MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, //Tag 9-14: PID 2-7 DRAM + { "PID3DRAM", { MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // + { "PID4DRAM", { MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // + { "PID5DRAM", { MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // + { "PID6DRAM", { MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // + { "PID7DRAM", { MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // + { "SPISRAM", { MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}}, //Tag 15: SPI SRAM data + { "", { MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID }} //End }; /* @@ -214,8 +219,8 @@ void heap_alloc_caps_init() { ESP_EARLY_LOGI(TAG, "Initializing heap allocator:"); for (i=0; regions[i].xSizeInBytes!=0; i++) { if (regions[i].xTag != -1) { - ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %d", i, - (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xTag); + ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %s", i, + (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, tag_desc[regions[i].xTag].name); } } //Initialize the malloc implementation. @@ -241,14 +246,14 @@ void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps ) uint32_t remCaps; for (prio=0; prio Date: Fri, 9 Dec 2016 16:17:26 +0800 Subject: [PATCH 2/7] Do not disable entire IRAM pool; instead disable only the bit that is used. This gives us 50K of iram at the moment. --- components/esp32/heap_alloc_caps.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 3ec70c9d7..a04cc8597 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -166,7 +166,7 @@ static void disable_mem_region(void *from, void *to) { ToDo: These are very dependent on the linker script, and the logic involving this works only because we're not using the SPI flash yet! If we enable that, this will break. ToDo: Rewrite by then. */ -extern int _bss_start, _heap_start; +extern int _bss_start, _heap_start, _init_start, _iram_text_end; /* Initialize the heap allocator. We pass it a bunch of region descriptors, but we need to modify those first to accommodate for @@ -177,11 +177,11 @@ Same with loading of apps. Same with using SPI RAM. void heap_alloc_caps_init() { int i; //Disable the bits of memory where this code is loaded. - disable_mem_region(&_bss_start, &_heap_start); + disable_mem_region(&_bss_start, &_heap_start); //DRAM used by bss/data static variables + disable_mem_region(&_init_start, &_iram_text_end); //IRAM used by code disable_mem_region((void*)0x3ffae000, (void*)0x3ffb0000); //knock out ROM data region disable_mem_region((void*)0x40070000, (void*)0x40078000); //CPU0 cache region disable_mem_region((void*)0x40078000, (void*)0x40080000); //CPU1 cache region - disable_mem_region((void*)0x40080000, (void*)0x400a0000); //pool 2-5 // TODO: this region should be checked, since we don't need to knock out all region finally disable_mem_region((void*)0x3ffe0000, (void*)0x3ffe8000); //knock out ROM data region @@ -216,11 +216,11 @@ void heap_alloc_caps_init() { } } - ESP_EARLY_LOGI(TAG, "Initializing heap allocator:"); + ESP_EARLY_LOGI(TAG, "Initializing. RAM available for heap:"); for (i=0; regions[i].xSizeInBytes!=0; i++) { if (regions[i].xTag != -1) { - ESP_EARLY_LOGI(TAG, "Region %02d: %08X len %08X tag %s", i, - (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, tag_desc[regions[i].xTag].name); + ESP_EARLY_LOGI(TAG, "At %08X len %08X (%d KiB): %s", + (int)regions[i].pucStartAddress, regions[i].xSizeInBytes, regions[i].xSizeInBytes/1024, tag_desc[regions[i].xTag].name); } } //Initialize the malloc implementation. @@ -267,3 +267,4 @@ void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps ) //Nothing usable found. return NULL; } + From 3f3cf397f74c8c0c2bf1a62eecb22f28e90abbe9 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Fri, 9 Dec 2016 16:19:24 +0800 Subject: [PATCH 3/7] Tabs -> spaces --- components/esp32/heap_alloc_caps.c | 4 +- components/freertos/heap_regions.c | 614 ++++++++++++++--------------- 2 files changed, 309 insertions(+), 309 deletions(-) diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index a04cc8597..7e6ce422c 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -36,8 +36,8 @@ hardwiring addresses. #define NO_PRIOS 3 typedef struct { - const char *name; - uint32_t prio[NO_PRIOS]; + const char *name; + uint32_t prio[NO_PRIOS]; } tag_desc_t; /* diff --git a/components/freertos/heap_regions.c b/components/freertos/heap_regions.c index 1abcdf3c6..51df477f2 100644 --- a/components/freertos/heap_regions.c +++ b/components/freertos/heap_regions.c @@ -10,12 +10,12 @@ the terms of the GNU General Public License (version 2) as published by the Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. - *************************************************************************** + *************************************************************************** >>! NOTE: The modification to the GPL is included to allow you to !<< >>! distribute a combined work that includes FreeRTOS without being !<< >>! obliged to provide the source code for proprietary components !<< >>! outside of the FreeRTOS kernel. !<< - *************************************************************************** + *************************************************************************** FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS @@ -37,17 +37,17 @@ *************************************************************************** http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading - the FAQ page "My application does not run, what could be wrong?". Have you - defined configASSERT()? + the FAQ page "My application does not run, what could be wrong?". Have you + defined configASSERT()? - http://www.FreeRTOS.org/support - In return for receiving this top quality - embedded software for free we request you assist our global community by - participating in the support forum. + http://www.FreeRTOS.org/support - In return for receiving this top quality + embedded software for free we request you assist our global community by + participating in the support forum. - http://www.FreeRTOS.org/training - Investing in training allows your team to - be as productive as possible as early as possible. Now you can receive - FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers - Ltd, and the world's leading authority on the world's leading RTOS. + http://www.FreeRTOS.org/training - Investing in training allows your team to + be as productive as possible as early as possible. Now you can receive + FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers + Ltd, and the world's leading authority on the world's leading RTOS. http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, including FreeRTOS+Trace - an indispensable productivity tool, a DOS @@ -85,9 +85,9 @@ * * typedef struct HeapRegion * { - * uint8_t *pucStartAddress; << Start address of a block of memory that will be part of the heap. - * size_t xSizeInBytes; << Size of the block of memory. - * BaseType_t xTag; << Tag + * uint8_t *pucStartAddress; << Start address of a block of memory that will be part of the heap. + * size_t xSizeInBytes; << Size of the block of memory. + * BaseType_t xTag; << Tag * } HeapRegionTagged_t; * * 'Tag' allows you to allocate memory of a certain type. Tag -1 is special; @@ -101,9 +101,9 @@ * * HeapRegionTagged_t xHeapRegions[] = * { - * { ( uint8_t * ) 0x80000000UL, 0x10000, 1 }, << Defines a block of 0x10000 bytes starting at address 0x80000000, tag 1 - * { ( uint8_t * ) 0x90000000UL, 0xa0000, 2 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000, tag 2 - * { NULL, 0, 0 } << Terminates the array. + * { ( uint8_t * ) 0x80000000UL, 0x10000, 1 }, << Defines a block of 0x10000 bytes starting at address 0x80000000, tag 1 + * { ( uint8_t * ) 0x90000000UL, 0xa0000, 2 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000, tag 2 + * { NULL, 0, 0 } << Terminates the array. * }; * * vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions(). @@ -141,18 +141,18 @@ task.h is included from an application file. */ #include "rom/ets_sys.h" /* Block sizes must not get too small. */ -#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( uxHeapStructSize << 1 ) ) +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( uxHeapStructSize << 1 ) ) /* Assumes 8bit bytes! */ -#define heapBITS_PER_BYTE ( ( size_t ) 8 ) +#define heapBITS_PER_BYTE ( ( size_t ) 8 ) /* Define the linked list structure. This is used to link free blocks in order of their memory address. */ typedef struct A_BLOCK_LINK { - struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ - size_t xBlockSize; /*<< The size of the free block. */ - BaseType_t xTag; /*<< Tag of this region */ + struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ + size_t xBlockSize; /*<< The size of the free block. */ + BaseType_t xTag; /*<< Tag of this region */ } BlockLink_t; //Mux to protect the memory status data @@ -172,7 +172,7 @@ static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert ); /* The size of the structure placed at the beginning of each allocated memory block must by correctly byte aligned. */ -static const uint32_t uxHeapStructSize = ( ( sizeof ( BlockLink_t ) + BLOCK_HEAD_LEN + BLOCK_TAIL_LEN + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); +static const uint32_t uxHeapStructSize = ( ( sizeof ( BlockLink_t ) + BLOCK_HEAD_LEN + BLOCK_TAIL_LEN + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); /* Create a couple of list links to mark the start and end of the list. */ static BlockLink_t xStart, *pxEnd = NULL; @@ -195,50 +195,50 @@ void *pvPortMallocTagged( size_t xWantedSize, BaseType_t tag ) BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; void *pvReturn = NULL; - /* The heap must be initialised before the first call to - prvPortMalloc(). */ - configASSERT( pxEnd ); + /* The heap must be initialised before the first call to + prvPortMalloc(). */ + configASSERT( pxEnd ); - taskENTER_CRITICAL(&xMallocMutex); - { - /* Check the requested block size is not so large that the top bit is - set. The top bit of the block size member of the BlockLink_t structure - is used to determine who owns the block - the application or the - kernel, so it must be free. */ - if( ( xWantedSize & xBlockAllocatedBit ) == 0 ) - { - /* The wanted size is increased so it can contain a BlockLink_t - structure in addition to the requested amount of bytes. */ - if( xWantedSize > 0 ) - { - xWantedSize += uxHeapStructSize; + taskENTER_CRITICAL(&xMallocMutex); + { + /* Check the requested block size is not so large that the top bit is + set. The top bit of the block size member of the BlockLink_t structure + is used to determine who owns the block - the application or the + kernel, so it must be free. */ + if( ( xWantedSize & xBlockAllocatedBit ) == 0 ) + { + /* The wanted size is increased so it can contain a BlockLink_t + structure in addition to the requested amount of bytes. */ + if( xWantedSize > 0 ) + { + xWantedSize += uxHeapStructSize; - /* Ensure that blocks are always aligned to the required number - of bytes. */ - if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) - { - /* Byte alignment required. */ - xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Ensure that blocks are always aligned to the required number + of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) - { - /* Traverse the list from the start (lowest address) block until - one of adequate size is found. */ - pxPreviousBlock = &xStart; - pxBlock = xStart.pxNextFreeBlock; - while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) ) - { -// ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock); + if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) + { + /* Traverse the list from the start (lowest address) block until + one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { +// ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock); #if (configENABLE_MEMORY_DEBUG == 1) { @@ -246,38 +246,38 @@ void *pvReturn = NULL; } #endif - pxPreviousBlock = pxBlock; - pxBlock = pxBlock->pxNextFreeBlock; - } + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; + } - /* If the end marker was not reached then a block of adequate size - was found. */ - if( pxBlock != pxEnd ) - { - /* Return the memory space pointed to - jumping over the - BlockLink_t structure at its start. */ - pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN); + /* If the end marker was not reached then a block of adequate size + was found. */ + if( pxBlock != pxEnd ) + { + /* Return the memory space pointed to - jumping over the + BlockLink_t structure at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN); - /* This block is being returned for use so must be taken out - of the list of free blocks. */ - pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + /* This block is being returned for use so must be taken out + of the list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; - /* If the block is larger than required it can be split into - two. */ + /* If the block is larger than required it can be split into + two. */ - if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) - { - /* This block is to be split into two. Create a new - block following the number of bytes requested. The void - cast is used to prevent byte alignment warnings from the - compiler. */ - pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize); + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + { + /* This block is to be split into two. Create a new + block following the number of bytes requested. The void + cast is used to prevent byte alignment warnings from the + compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize); - /* Calculate the sizes of two blocks split from the - single block. */ - pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; - pxNewBlockLink->xTag = tag; - pxBlock->xBlockSize = xWantedSize; + /* Calculate the sizes of two blocks split from the + single block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxNewBlockLink->xTag = tag; + pxBlock->xBlockSize = xWantedSize; #if (configENABLE_MEMORY_DEBUG == 1) { @@ -286,29 +286,29 @@ void *pvReturn = NULL; #endif - /* Insert the new block into the list of free blocks. */ - prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - xFreeBytesRemaining -= pxBlock->xBlockSize; + xFreeBytesRemaining -= pxBlock->xBlockSize; - if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) - { - xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) + { + xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - /* The block is being returned - it is allocated and owned - by the application and has no "next" block. */ - pxBlock->xBlockSize |= xBlockAllocatedBit; - pxBlock->pxNextFreeBlock = NULL; + /* The block is being returned - it is allocated and owned + by the application and has no "next" block. */ + pxBlock->xBlockSize |= xBlockAllocatedBit; + pxBlock->pxNextFreeBlock = NULL; #if (configENABLE_MEMORY_DEBUG == 1) { @@ -316,41 +316,41 @@ void *pvReturn = NULL; mem_malloc_block(pxBlock); } #endif - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - traceMALLOC( pvReturn, xWantedSize ); - } - taskEXIT_CRITICAL(&xMallocMutex); + traceMALLOC( pvReturn, xWantedSize ); + } + taskEXIT_CRITICAL(&xMallocMutex); - #if( configUSE_MALLOC_FAILED_HOOK == 1 ) - { - if( pvReturn == NULL ) - { - extern void vApplicationMallocFailedHook( void ); - vApplicationMallocFailedHook(); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - #endif + #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + { + if( pvReturn == NULL ) + { + extern void vApplicationMallocFailedHook( void ); + vApplicationMallocFailedHook(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif - return pvReturn; + return pvReturn; } /*-----------------------------------------------------------*/ @@ -359,14 +359,14 @@ void vPortFree( void *pv ) uint8_t *puc = ( uint8_t * ) pv; BlockLink_t *pxLink; - if( pv != NULL ) - { - /* The memory being freed will have an BlockLink_t structure immediately - before it. */ - puc -= (uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN) ; + if( pv != NULL ) + { + /* The memory being freed will have an BlockLink_t structure immediately + before it. */ + puc -= (uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN) ; - /* This casting is to keep the compiler from issuing warnings. */ - pxLink = ( void * ) puc; + /* This casting is to keep the compiler from issuing warnings. */ + pxLink = ( void * ) puc; #if (configENABLE_MEMORY_DEBUG == 1) { @@ -377,49 +377,49 @@ BlockLink_t *pxLink; } #endif - /* Check the block is actually allocated. */ - configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); - configASSERT( pxLink->pxNextFreeBlock == NULL ); + /* Check the block is actually allocated. */ + configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( pxLink->pxNextFreeBlock == NULL ); - if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) - { - if( pxLink->pxNextFreeBlock == NULL ) - { - /* The block is being returned to the heap - it is no longer - allocated. */ - pxLink->xBlockSize &= ~xBlockAllocatedBit; + if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) + { + if( pxLink->pxNextFreeBlock == NULL ) + { + /* The block is being returned to the heap - it is no longer + allocated. */ + pxLink->xBlockSize &= ~xBlockAllocatedBit; - taskENTER_CRITICAL(&xMallocMutex); - { - /* Add this block to the list of free blocks. */ - xFreeBytesRemaining += pxLink->xBlockSize; - traceFREE( pv, pxLink->xBlockSize ); - prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); - } - taskEXIT_CRITICAL(&xMallocMutex); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - } + taskENTER_CRITICAL(&xMallocMutex); + { + /* Add this block to the list of free blocks. */ + xFreeBytesRemaining += pxLink->xBlockSize; + traceFREE( pv, pxLink->xBlockSize ); + prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + } + taskEXIT_CRITICAL(&xMallocMutex); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } } /*-----------------------------------------------------------*/ size_t xPortGetFreeHeapSize( void ) { - return xFreeBytesRemaining; + return xFreeBytesRemaining; } /*-----------------------------------------------------------*/ size_t xPortGetMinimumEverFreeHeapSize( void ) { - return xMinimumEverFreeBytesRemaining; + return xMinimumEverFreeBytesRemaining; } /*-----------------------------------------------------------*/ @@ -428,59 +428,59 @@ static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert ) BlockLink_t *pxIterator; uint8_t *puc; - /* Iterate through the list until a block is found that has a higher address - than the block being inserted. */ - for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ) - { - /* Nothing to do here, just iterate to the right position. */ - } + /* Iterate through the list until a block is found that has a higher address + than the block being inserted. */ + for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ) + { + /* Nothing to do here, just iterate to the right position. */ + } - /* Do the block being inserted, and the block it is being inserted after - make a contiguous block of memory, and are the tags the same? */ - puc = ( uint8_t * ) pxIterator; - if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert && pxBlockToInsert->xTag==pxIterator->xTag) - { - pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; - pxBlockToInsert = pxIterator; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Do the block being inserted, and the block it is being inserted after + make a contiguous block of memory, and are the tags the same? */ + puc = ( uint8_t * ) pxIterator; + if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert && pxBlockToInsert->xTag==pxIterator->xTag) + { + pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; + pxBlockToInsert = pxIterator; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } - /* Do the block being inserted, and the block it is being inserted before - make a contiguous block of memory, and are the tags the same */ - puc = ( uint8_t * ) pxBlockToInsert; - if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock && pxBlockToInsert->xTag==pxIterator->pxNextFreeBlock->xTag ) - { - if( pxIterator->pxNextFreeBlock != pxEnd ) - { - /* Form one big block from the two blocks. */ - pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize; - pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock; - } - else - { - pxBlockToInsert->pxNextFreeBlock = pxEnd; - } - } - else - { - pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; - } + /* Do the block being inserted, and the block it is being inserted before + make a contiguous block of memory, and are the tags the same */ + puc = ( uint8_t * ) pxBlockToInsert; + if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock && pxBlockToInsert->xTag==pxIterator->pxNextFreeBlock->xTag ) + { + if( pxIterator->pxNextFreeBlock != pxEnd ) + { + /* Form one big block from the two blocks. */ + pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize; + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock; + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxEnd; + } + } + else + { + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; + } - /* If the block being inserted plugged a gap, so was merged with the block - before and the block after, then it's pxNextFreeBlock pointer will have - already been set, and should not be set here as that would make it point - to itself. */ - if( pxIterator != pxBlockToInsert ) - { - pxIterator->pxNextFreeBlock = pxBlockToInsert; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* If the block being inserted plugged a gap, so was merged with the block + before and the block after, then it's pxNextFreeBlock pointer will have + already been set, and should not be set here as that would make it point + to itself. */ + if( pxIterator != pxBlockToInsert ) + { + pxIterator->pxNextFreeBlock = pxBlockToInsert; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } } /*-----------------------------------------------------------*/ @@ -493,90 +493,90 @@ BaseType_t xDefinedRegions = 0, xRegIdx = 0; uint32_t ulAddress; const HeapRegionTagged_t *pxHeapRegion; - /* Can only call once! */ - configASSERT( pxEnd == NULL ); + /* Can only call once! */ + configASSERT( pxEnd == NULL ); - vPortCPUInitializeMutex(&xMallocMutex); + vPortCPUInitializeMutex(&xMallocMutex); - pxHeapRegion = &( pxHeapRegions[ xRegIdx ] ); + pxHeapRegion = &( pxHeapRegions[ xRegIdx ] ); - while( pxHeapRegion->xSizeInBytes > 0 ) - { - if ( pxHeapRegion->xTag == -1 ) { - /* Move onto the next HeapRegionTagged_t structure. */ - xRegIdx++; - pxHeapRegion = &( pxHeapRegions[ xRegIdx ] ); - continue; - } + while( pxHeapRegion->xSizeInBytes > 0 ) + { + if ( pxHeapRegion->xTag == -1 ) { + /* Move onto the next HeapRegionTagged_t structure. */ + xRegIdx++; + pxHeapRegion = &( pxHeapRegions[ xRegIdx ] ); + continue; + } - xTotalRegionSize = pxHeapRegion->xSizeInBytes; + xTotalRegionSize = pxHeapRegion->xSizeInBytes; - /* Ensure the heap region starts on a correctly aligned boundary. */ - ulAddress = ( uint32_t ) pxHeapRegion->pucStartAddress; - if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 ) - { - ulAddress += ( portBYTE_ALIGNMENT - 1 ); - ulAddress &= ~portBYTE_ALIGNMENT_MASK; + /* Ensure the heap region starts on a correctly aligned boundary. */ + ulAddress = ( uint32_t ) pxHeapRegion->pucStartAddress; + if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 ) + { + ulAddress += ( portBYTE_ALIGNMENT - 1 ); + ulAddress &= ~portBYTE_ALIGNMENT_MASK; - /* Adjust the size for the bytes lost to alignment. */ - xTotalRegionSize -= ulAddress - ( uint32_t ) pxHeapRegion->pucStartAddress; - } + /* Adjust the size for the bytes lost to alignment. */ + xTotalRegionSize -= ulAddress - ( uint32_t ) pxHeapRegion->pucStartAddress; + } - pucAlignedHeap = ( uint8_t * ) ulAddress; + pucAlignedHeap = ( uint8_t * ) ulAddress; - /* Set xStart if it has not already been set. */ - if( xDefinedRegions == 0 ) - { - /* xStart is used to hold a pointer to the first item in the list of - free blocks. The void cast is used to prevent compiler warnings. */ - xStart.pxNextFreeBlock = ( BlockLink_t * ) (pucAlignedHeap + BLOCK_HEAD_LEN); - xStart.xBlockSize = ( size_t ) 0; - } - else - { - /* Should only get here if one region has already been added to the - heap. */ - configASSERT( pxEnd != NULL ); + /* Set xStart if it has not already been set. */ + if( xDefinedRegions == 0 ) + { + /* xStart is used to hold a pointer to the first item in the list of + free blocks. The void cast is used to prevent compiler warnings. */ + xStart.pxNextFreeBlock = ( BlockLink_t * ) (pucAlignedHeap + BLOCK_HEAD_LEN); + xStart.xBlockSize = ( size_t ) 0; + } + else + { + /* Should only get here if one region has already been added to the + heap. */ + configASSERT( pxEnd != NULL ); - /* Check blocks are passed in with increasing start addresses. */ - configASSERT( ulAddress > ( uint32_t ) pxEnd ); - } + /* Check blocks are passed in with increasing start addresses. */ + configASSERT( ulAddress > ( uint32_t ) pxEnd ); + } - /* Remember the location of the end marker in the previous region, if - any. */ - pxPreviousFreeBlock = pxEnd; + /* Remember the location of the end marker in the previous region, if + any. */ + pxPreviousFreeBlock = pxEnd; - /* pxEnd is used to mark the end of the list of free blocks and is - inserted at the end of the region space. */ - ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalRegionSize; - ulAddress -= uxHeapStructSize; - ulAddress &= ~portBYTE_ALIGNMENT_MASK; - pxEnd = ( BlockLink_t * ) (ulAddress + BLOCK_HEAD_LEN); - pxEnd->xBlockSize = 0; - pxEnd->pxNextFreeBlock = NULL; - pxEnd->xTag = -1; + /* pxEnd is used to mark the end of the list of free blocks and is + inserted at the end of the region space. */ + ulAddress = ( ( uint32_t ) pucAlignedHeap ) + xTotalRegionSize; + ulAddress -= uxHeapStructSize; + ulAddress &= ~portBYTE_ALIGNMENT_MASK; + pxEnd = ( BlockLink_t * ) (ulAddress + BLOCK_HEAD_LEN); + pxEnd->xBlockSize = 0; + pxEnd->pxNextFreeBlock = NULL; + pxEnd->xTag = -1; - /* To start with there is a single free block in this region that is - sized to take up the entire heap region minus the space taken by the - free block structure. */ - pxFirstFreeBlockInRegion = ( BlockLink_t * ) (pucAlignedHeap + BLOCK_HEAD_LEN); - pxFirstFreeBlockInRegion->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlockInRegion + BLOCK_HEAD_LEN; - pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd; - pxFirstFreeBlockInRegion->xTag=pxHeapRegion->xTag; + /* To start with there is a single free block in this region that is + sized to take up the entire heap region minus the space taken by the + free block structure. */ + pxFirstFreeBlockInRegion = ( BlockLink_t * ) (pucAlignedHeap + BLOCK_HEAD_LEN); + pxFirstFreeBlockInRegion->xBlockSize = ulAddress - ( uint32_t ) pxFirstFreeBlockInRegion + BLOCK_HEAD_LEN; + pxFirstFreeBlockInRegion->pxNextFreeBlock = pxEnd; + pxFirstFreeBlockInRegion->xTag=pxHeapRegion->xTag; - /* If this is not the first region that makes up the entire heap space - then link the previous region to this region. */ - if( pxPreviousFreeBlock != NULL ) - { - pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion; - } + /* If this is not the first region that makes up the entire heap space + then link the previous region to this region. */ + if( pxPreviousFreeBlock != NULL ) + { + pxPreviousFreeBlock->pxNextFreeBlock = pxFirstFreeBlockInRegion; + } - xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; + xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; - /* Move onto the next HeapRegionTagged_t structure. */ - xDefinedRegions++; - xRegIdx++; - pxHeapRegion = &( pxHeapRegions[ xRegIdx ] ); + /* Move onto the next HeapRegionTagged_t structure. */ + xDefinedRegions++; + xRegIdx++; + pxHeapRegion = &( pxHeapRegions[ xRegIdx ] ); #if (configENABLE_MEMORY_DEBUG == 1) { @@ -584,16 +584,16 @@ const HeapRegionTagged_t *pxHeapRegion; mem_init_dog(pxEnd); } #endif - } + } - xMinimumEverFreeBytesRemaining = xTotalHeapSize; - xFreeBytesRemaining = xTotalHeapSize; + xMinimumEverFreeBytesRemaining = xTotalHeapSize; + xFreeBytesRemaining = xTotalHeapSize; - /* Check something was actually defined before it is accessed. */ - configASSERT( xTotalHeapSize ); + /* Check something was actually defined before it is accessed. */ + configASSERT( xTotalHeapSize ); - /* Work out the position of the top bit in a size_t variable. */ - xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); + /* Work out the position of the top bit in a size_t variable. */ + xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); #if (configENABLE_MEMORY_DEBUG == 1) { From 293ad4cd36481f988d14f22ec5a31aa900674a9a Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Fri, 9 Dec 2016 17:13:45 +0800 Subject: [PATCH 4/7] Add xPortGetFreeHeapSizeCaps and xPortGetMinimumEverFreeHeapSizeCaps plus everything it entails. Allows querying the available memory for various capabilities. Also: xPortGetFreeHeapSize and xPortGetMinimumEverFreeHeapSize now return the expected value. Bonus: the linked list used in the allocator is now 4 bytes smaller, which should save some memory. --- components/esp32/heap_alloc_caps.c | 50 ++++ .../esp32/include/esp_heap_alloc_caps.h | 2 + components/freertos/heap_regions.c | 232 ++++++++---------- components/freertos/heap_regions_debug.c | 20 +- .../freertos/include/freertos/heap_regions.h | 6 +- .../include/freertos/heap_regions_debug.h | 2 +- 6 files changed, 175 insertions(+), 137 deletions(-) diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 7e6ce422c..7ce8ba5ca 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -43,6 +43,7 @@ typedef struct { /* Tag descriptors. These describe the capabilities of a bit of memory that's tagged with the index into this table. Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones can't fulfill the memory request. +Make sure there are never more than HEAPREGIONS_MAX_TAGCOUNT (in heap_regions.h) tags (ex the last empty marker) */ static const tag_desc_t tag_desc[]={ { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }}, //Tag 0: Plain ole D-port RAM @@ -268,3 +269,52 @@ void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps ) return NULL; } + +size_t xPortGetFreeHeapSizeCaps( uint32_t caps ) +{ + int prio; + int tag; + size_t ret=0; + for (prio=0; prio 0 ) { - /* The wanted size is increased so it can contain a BlockLink_t - structure in addition to the requested amount of bytes. */ - if( xWantedSize > 0 ) - { - xWantedSize += uxHeapStructSize; + xWantedSize += uxHeapStructSize; - /* Ensure that blocks are always aligned to the required number - of bytes. */ - if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) - { - /* Byte alignment required. */ - xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + /* Ensure that blocks are always aligned to the required number + of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); } else { - mtCOVERAGE_TEST_MARKER(); + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining[ tag ] ) ) + { + /* Traverse the list from the start (lowest address) block until + one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { +// ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock); + + #if (configENABLE_MEMORY_DEBUG == 1) + { + mem_check_block(pxBlock); + } + #endif + + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; } - if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) + /* If the end marker was not reached then a block of adequate size + was found. */ + if( pxBlock != pxEnd ) { - /* Traverse the list from the start (lowest address) block until - one of adequate size is found. */ - pxPreviousBlock = &xStart; - pxBlock = xStart.pxNextFreeBlock; - while( ( ( pxBlock->xTag != tag ) || ( pxBlock->xBlockSize < xWantedSize ) ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + /* Return the memory space pointed to - jumping over the + BlockLink_t structure at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN); + + /* This block is being returned for use so must be taken out + of the list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into + two. */ + + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) { -// ets_printf("Block %x -> %x\n", (uint32_t)pxBlock, (uint32_t)pxBlock->pxNextFreeBlock); + /* This block is to be split into two. Create a new + block following the number of bytes requested. The void + cast is used to prevent byte alignment warnings from the + compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize); - #if (configENABLE_MEMORY_DEBUG == 1) - { - mem_check_block(pxBlock); - } - #endif + /* Calculate the sizes of two blocks split from the + single block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxNewBlockLink->xTag = tag; + pxBlock->xBlockSize = xWantedSize; - pxPreviousBlock = pxBlock; - pxBlock = pxBlock->pxNextFreeBlock; - } - - /* If the end marker was not reached then a block of adequate size - was found. */ - if( pxBlock != pxEnd ) - { - /* Return the memory space pointed to - jumping over the - BlockLink_t structure at its start. */ - pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + uxHeapStructSize - BLOCK_TAIL_LEN - BLOCK_HEAD_LEN); - - /* This block is being returned for use so must be taken out - of the list of free blocks. */ - pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; - - /* If the block is larger than required it can be split into - two. */ - - if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) - { - /* This block is to be split into two. Create a new - block following the number of bytes requested. The void - cast is used to prevent byte alignment warnings from the - compiler. */ - pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize); - - /* Calculate the sizes of two blocks split from the - single block. */ - pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; - pxNewBlockLink->xTag = tag; - pxBlock->xBlockSize = xWantedSize; - - #if (configENABLE_MEMORY_DEBUG == 1) - { - mem_init_dog(pxNewBlockLink); - } - #endif + #if (configENABLE_MEMORY_DEBUG == 1) + { + mem_init_dog(pxNewBlockLink); + } + #endif - /* Insert the new block into the list of free blocks. */ - prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - xFreeBytesRemaining -= pxBlock->xBlockSize; - - if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) - { - xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } - - /* The block is being returned - it is allocated and owned - by the application and has no "next" block. */ - pxBlock->xBlockSize |= xBlockAllocatedBit; - pxBlock->pxNextFreeBlock = NULL; - - #if (configENABLE_MEMORY_DEBUG == 1) - { - mem_init_dog(pxBlock); - mem_malloc_block(pxBlock); - } - #endif + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); } else { mtCOVERAGE_TEST_MARKER(); } + + xFreeBytesRemaining[ tag ] -= pxBlock->xBlockSize; + + if( xFreeBytesRemaining[ tag ] < xMinimumEverFreeBytesRemaining[ tag ] ) + { + xMinimumEverFreeBytesRemaining[ tag ] = xFreeBytesRemaining[ tag ]; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* The block is being returned - it is allocated and owned + by the application and has no "next" block. */ + pxBlock->xAllocated = 1; + pxBlock->pxNextFreeBlock = NULL; + + #if (configENABLE_MEMORY_DEBUG == 1) + { + mem_init_dog(pxBlock); + mem_malloc_block(pxBlock); + } + #endif } else { @@ -378,21 +364,21 @@ BlockLink_t *pxLink; #endif /* Check the block is actually allocated. */ - configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( ( pxLink->xAllocated ) != 0 ); configASSERT( pxLink->pxNextFreeBlock == NULL ); - if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) + if( pxLink->xAllocated != 0 ) { if( pxLink->pxNextFreeBlock == NULL ) { /* The block is being returned to the heap - it is no longer allocated. */ - pxLink->xBlockSize &= ~xBlockAllocatedBit; + pxLink->xAllocated = 0; taskENTER_CRITICAL(&xMallocMutex); { /* Add this block to the list of free blocks. */ - xFreeBytesRemaining += pxLink->xBlockSize; + xFreeBytesRemaining[ pxLink->xTag ] += pxLink->xBlockSize; traceFREE( pv, pxLink->xBlockSize ); prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); } @@ -411,15 +397,15 @@ BlockLink_t *pxLink; } /*-----------------------------------------------------------*/ -size_t xPortGetFreeHeapSize( void ) +size_t xPortGetFreeHeapSizeTagged( BaseType_t tag ) { - return xFreeBytesRemaining; + return xFreeBytesRemaining[ tag ]; } /*-----------------------------------------------------------*/ -size_t xPortGetMinimumEverFreeHeapSize( void ) +size_t xPortGetMinimumEverFreeHeapSizeTagged( BaseType_t tag ) { - return xMinimumEverFreeBytesRemaining; + return xMinimumEverFreeBytesRemaining[ tag ]; } /*-----------------------------------------------------------*/ @@ -509,6 +495,7 @@ const HeapRegionTagged_t *pxHeapRegion; continue; } + configASSERT(pxHeapRegion->xTag < HEAPREGIONS_MAX_TAGCOUNT); xTotalRegionSize = pxHeapRegion->xSizeInBytes; /* Ensure the heap region starts on a correctly aligned boundary. */ @@ -572,6 +559,8 @@ const HeapRegionTagged_t *pxHeapRegion; } xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; + xMinimumEverFreeBytesRemaining[ pxHeapRegion->xTag ] += pxFirstFreeBlockInRegion->xBlockSize; + xFreeBytesRemaining[ pxHeapRegion->xTag ] += pxFirstFreeBlockInRegion->xBlockSize; /* Move onto the next HeapRegionTagged_t structure. */ xDefinedRegions++; @@ -586,14 +575,9 @@ const HeapRegionTagged_t *pxHeapRegion; #endif } - xMinimumEverFreeBytesRemaining = xTotalHeapSize; - xFreeBytesRemaining = xTotalHeapSize; - /* Check something was actually defined before it is accessed. */ configASSERT( xTotalHeapSize ); - /* Work out the position of the top bit in a size_t variable. */ - xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ); #if (configENABLE_MEMORY_DEBUG == 1) { diff --git a/components/freertos/heap_regions_debug.c b/components/freertos/heap_regions_debug.c index d8d444a53..f221e516b 100644 --- a/components/freertos/heap_regions_debug.c +++ b/components/freertos/heap_regions_debug.c @@ -12,19 +12,17 @@ static size_t g_heap_struct_size; static mem_dbg_ctl_t g_mem_dbg; char g_mem_print = 0; static portMUX_TYPE *g_malloc_mutex = NULL; -static unsigned int g_alloc_bit; #define MEM_DEBUG(...) -void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex, unsigned int alloc_bit) +void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex) { - MEM_DEBUG("size=%d start=%p end=%p mutex=%p alloc_bit=0x%x\n", size, start, end, mutex, alloc_bit); + MEM_DEBUG("size=%d start=%p end=%p mutex=%p%x\n", size, start, end, mutex); memset(&g_mem_dbg, 0, sizeof(g_mem_dbg)); memset(&g_malloc_list, 0, sizeof(g_malloc_list)); g_malloc_mutex = mutex; g_heap_struct_size = size; g_free_list = start; g_end = end; - g_alloc_bit = alloc_bit; } void mem_debug_push(char type, void *addr) @@ -35,9 +33,9 @@ void mem_debug_push(char type, void *addr) MEM_DEBUG("push type=%d addr=%p\n", type, addr); if (g_mem_print){ if (type == DEBUG_TYPE_MALLOC){ - ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size&(~g_alloc_bit), addr); + ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size, addr); } else { - ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size&(~g_alloc_bit), addr); + ets_printf("task=%s t=%s s=%u a=%p\n", debug_b->head.task?debug_b->head.task:"", type==DEBUG_TYPE_MALLOC?"m":"f", b->size, addr); } } else { mem_dbg_info_t *info = &g_mem_dbg.info[g_mem_dbg.cnt%DEBUG_MAX_INFO_NUM]; @@ -58,7 +56,7 @@ void mem_debug_malloc_show(void) while (b){ d = DEBUG_BLOCK(b); d->head.task[3] = '\0'; - ets_printf("t=%s s=%u a=%p\n", d->head.task?d->head.task:"", b->size&(~g_alloc_bit), b); + ets_printf("t=%s s=%u a=%p\n", d->head.task?d->head.task:"", b->size, b); b = b->next; } taskEXIT_CRITICAL(g_malloc_mutex); @@ -140,7 +138,7 @@ void mem_malloc_show(void) while (b){ debug_b = DEBUG_BLOCK(b); - ets_printf("%s %p %p %u\n", debug_b->head.task, debug_b, b, b->size&(~g_alloc_bit)); + ets_printf("%s %p %p %u\n", debug_b->head.task, debug_b, b, b->size); b = b->next; } } @@ -149,7 +147,7 @@ void mem_malloc_block(void *data) { os_block_t *b = (os_block_t*)data; - MEM_DEBUG("mem malloc block data=%p, size=%u\n", data, b->size&(~g_alloc_bit)); + MEM_DEBUG("mem malloc block data=%p, size=%u\n", data, b->size); mem_debug_push(DEBUG_TYPE_MALLOC, data); if (b){ @@ -165,7 +163,7 @@ void mem_free_block(void *data) os_block_t *pre = &g_malloc_list; debug_block_t *debug_b; - MEM_DEBUG("mem free block data=%p, size=%d\n", data, del->size&(~g_alloc_bit)); + MEM_DEBUG("mem free block data=%p, size=%d\n", data, del->size); mem_debug_push(DEBUG_TYPE_FREE, data); if (!del) { @@ -183,7 +181,7 @@ void mem_free_block(void *data) } debug_b = DEBUG_BLOCK(del); - ets_printf("%s %p %p %u already free\n", debug_b->head.task, debug_b, del, del->size&(~g_alloc_bit)); + ets_printf("%s %p %p %u already free\n", debug_b->head.task, debug_b, del, del->size); mem_malloc_show(); abort(); } diff --git a/components/freertos/include/freertos/heap_regions.h b/components/freertos/include/freertos/heap_regions.h index aedea42a1..3e632dac7 100644 --- a/components/freertos/include/freertos/heap_regions.h +++ b/components/freertos/include/freertos/heap_regions.h @@ -16,6 +16,9 @@ #include "freertos/FreeRTOS.h" +/* The maximum amount of tags in use */ +#define HEAPREGIONS_MAX_TAGCOUNT 16 + typedef struct HeapRegionTagged { @@ -28,7 +31,8 @@ typedef struct HeapRegionTagged void vPortDefineHeapRegionsTagged( const HeapRegionTagged_t * const pxHeapRegions ); void *pvPortMallocTagged( size_t xWantedSize, BaseType_t tag ); - +size_t xPortGetMinimumEverFreeHeapSizeTagged( BaseType_t tag ); +size_t xPortGetFreeHeapSizeTagged( BaseType_t tag ); #endif \ No newline at end of file diff --git a/components/freertos/include/freertos/heap_regions_debug.h b/components/freertos/include/freertos/heap_regions_debug.h index 81bf1d6c3..6ab4681f1 100644 --- a/components/freertos/include/freertos/heap_regions_debug.h +++ b/components/freertos/include/freertos/heap_regions_debug.h @@ -60,7 +60,7 @@ typedef struct _mem_dbg_ctl{ extern void mem_check_block(void * data); extern void mem_init_dog(void *data); -extern void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex, unsigned int alloc_bit); +extern void mem_debug_init(size_t size, void *start, void *end, portMUX_TYPE *mutex); extern void mem_malloc_block(void *data); extern void mem_free_block(void *data); extern void mem_check_all(void* pv); From 1e117dc3d31513928528bd178611f67b8ffde1f7 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Tue, 13 Dec 2016 17:01:10 +0800 Subject: [PATCH 5/7] Fix small things noticed in MR, add documentation --- components/esp32/heap_alloc_caps.c | 9 ++- .../esp32/include/esp_heap_alloc_caps.h | 66 +++++++++++++--- components/freertos/heap_regions.c | 6 +- .../freertos/include/freertos/heap_regions.h | 59 ++++++++++++-- docs/Doxyfile | 4 +- docs/api/mem_alloc.rst | 78 +++++++++++++++++++ docs/index.rst | 4 +- 7 files changed, 202 insertions(+), 24 deletions(-) create mode 100644 docs/api/mem_alloc.rst diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 7ce8ba5ca..511903c43 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -164,8 +164,9 @@ static void disable_mem_region(void *from, void *to) { /* -ToDo: These are very dependent on the linker script, and the logic involving this works only -because we're not using the SPI flash yet! If we enable that, this will break. ToDo: Rewrite by then. +Warning: These variables are assumed to have the start and end of the data and iram +area used statically by the program, respectively. These variables are defined in the ld +file. */ extern int _bss_start, _heap_start, _init_start, _iram_text_end; @@ -177,6 +178,8 @@ Same with loading of apps. Same with using SPI RAM. */ void heap_alloc_caps_init() { int i; + //Compile-time assert to see if we don't have more tags than is set in heap_regions.h + _Static_assert((sizeof(tag_desc)/sizeof(tag_desc[0]))-1 <= HEAPREGIONS_MAX_TAGCOUNT, "More than HEAPREGIONS_MAX_TAGCOUNT tags defined!"); //Disable the bits of memory where this code is loaded. disable_mem_region(&_bss_start, &_heap_start); //DRAM used by bss/data static variables disable_mem_region(&_init_start, &_iram_text_end); //IRAM used by code @@ -217,7 +220,7 @@ void heap_alloc_caps_init() { } } - ESP_EARLY_LOGI(TAG, "Initializing. RAM available for heap:"); + ESP_EARLY_LOGI(TAG, "Initializing. RAM available for dynamic allocation:"); for (i=0; regions[i].xSizeInBytes!=0; i++) { if (regions[i].xTag != -1) { ESP_EARLY_LOGI(TAG, "At %08X len %08X (%d KiB): %s", diff --git a/components/esp32/include/esp_heap_alloc_caps.h b/components/esp32/include/esp_heap_alloc_caps.h index 42bc614c2..21c24de6b 100644 --- a/components/esp32/include/esp_heap_alloc_caps.h +++ b/components/esp32/include/esp_heap_alloc_caps.h @@ -14,23 +14,65 @@ #ifndef HEAP_ALLOC_CAPS_H #define HEAP_ALLOC_CAPS_H -#define MALLOC_CAP_EXEC (1<<0) //Memory must be able to run executable code -#define MALLOC_CAP_32BIT (1<<1) //Memory must allow for aligned 32-bit data accesses -#define MALLOC_CAP_8BIT (1<<2) //Memory must allow for 8/16/...-bit data accesses -#define MALLOC_CAP_DMA (1<<3) //Memory must be able to accessed by DMA -#define MALLOC_CAP_PID2 (1<<4) //Memory must be mapped to PID2 memory space -#define MALLOC_CAP_PID3 (1<<5) //Memory must be mapped to PID3 memory space -#define MALLOC_CAP_PID4 (1<<6) //Memory must be mapped to PID4 memory space -#define MALLOC_CAP_PID5 (1<<7) //Memory must be mapped to PID5 memory space -#define MALLOC_CAP_PID6 (1<<8) //Memory must be mapped to PID6 memory space -#define MALLOC_CAP_PID7 (1<<9) //Memory must be mapped to PID7 memory space -#define MALLOC_CAP_SPISRAM (1<<10) //Memory must be in SPI SRAM -#define MALLOC_CAP_INVALID (1<<31) //Memory can't be used / list end marker +/** + * @brief Flags to indicate the capabilities of the various memory systems + */ +#define MALLOC_CAP_EXEC (1<<0) ///< Memory must be able to run executable code +#define MALLOC_CAP_32BIT (1<<1) ///< Memory must allow for aligned 32-bit data accesses +#define MALLOC_CAP_8BIT (1<<2) ///< Memory must allow for 8/16/...-bit data accesses +#define MALLOC_CAP_DMA (1<<3) ///< Memory must be able to accessed by DMA +#define MALLOC_CAP_PID2 (1<<4) ///< Memory must be mapped to PID2 memory space +#define MALLOC_CAP_PID3 (1<<5) ///< Memory must be mapped to PID3 memory space +#define MALLOC_CAP_PID4 (1<<6) ///< Memory must be mapped to PID4 memory space +#define MALLOC_CAP_PID5 (1<<7) ///< Memory must be mapped to PID5 memory space +#define MALLOC_CAP_PID6 (1<<8) ///< Memory must be mapped to PID6 memory space +#define MALLOC_CAP_PID7 (1<<9) ///< Memory must be mapped to PID7 memory space +#define MALLOC_CAP_SPISRAM (1<<10) ///< Memory must be in SPI SRAM +#define MALLOC_CAP_INVALID (1<<31) ///< Memory can't be used / list end marker +/** + * @brief Initialize the capability-aware heap allocator. + * + * For the ESP32, this is called once in the startup code. + */ void heap_alloc_caps_init(); + +/** + * @brief Allocate a chunk of memory which has the given capabilities + * + * @param xWantedSize 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 *pvPortMallocCaps(size_t xWantedSize, uint32_t caps); + +/** + * @brief Get the total free size of all the regions that have the given capabilities + * + * This function takes all regions capable of having the given capabilities allocated in them + * and adds up the free space they have. + * + * @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type + * of memory + * + * @return Amount of free bytes in the regions + */ size_t xPortGetFreeHeapSizeCaps( uint32_t caps ); + +/** + * @brief Get the total minimum free memory of all regions with the given capabilities + * + * This adds all the lowmarks of the regions capable of delivering the memory with the + * given capabilities + * + * @param caps Bitwise OR of MALLOC_CAP_* flags indicating the type + * of memory + * + * @return Amount of free bytes in the regions + */ size_t xPortGetMinimumEverFreeHeapSizeCaps( uint32_t caps ); #endif \ No newline at end of file diff --git a/components/freertos/heap_regions.c b/components/freertos/heap_regions.c index 6e1cb103f..5ff1f2817 100644 --- a/components/freertos/heap_regions.c +++ b/components/freertos/heap_regions.c @@ -147,8 +147,9 @@ task.h is included from an application file. */ #define heapBITS_PER_BYTE ( ( size_t ) 8 ) /* Define the linked list structure. This is used to link free blocks in order -of their memory address. */ -/* This is optimized and assumes a region is never larger than 16MiB. */ + of their memory address. This is optimized for size of the linked list struct + and assumes a region is never larger than 16MiB. */ +#define HEAPREGIONS_MAX_REGIONSIZE (16*1024*1024) typedef struct A_BLOCK_LINK { struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ @@ -496,6 +497,7 @@ const HeapRegionTagged_t *pxHeapRegion; } configASSERT(pxHeapRegion->xTag < HEAPREGIONS_MAX_TAGCOUNT); + configASSERT(pxHeapRegion->xSizeInBytes < HEAPREGIONS_MAX_REGIONSIZE); xTotalRegionSize = pxHeapRegion->xSizeInBytes; /* Ensure the heap region starts on a correctly aligned boundary. */ diff --git a/components/freertos/include/freertos/heap_regions.h b/components/freertos/include/freertos/heap_regions.h index 3e632dac7..30d0dcb39 100644 --- a/components/freertos/include/freertos/heap_regions.h +++ b/components/freertos/include/freertos/heap_regions.h @@ -19,19 +19,68 @@ /* The maximum amount of tags in use */ #define HEAPREGIONS_MAX_TAGCOUNT 16 - +/** + * @brief Structure to define a memory region + */ typedef struct HeapRegionTagged { - uint8_t *pucStartAddress; - size_t xSizeInBytes; - BaseType_t xTag; - uint32_t xExecAddr; + uint8_t *pucStartAddress; ///< Start address of the region + size_t xSizeInBytes; ///< Size of the region + BaseType_t xTag; ///< Tag for the region + uint32_t xExecAddr; ///< If non-zero, indicates the region also has an alias in IRAM. } HeapRegionTagged_t; +/** + * @brief Initialize the heap allocator by feeding it the usable memory regions and their tags. + * + * This takes an array of heapRegionTagged_t structs, the last entry of which is a dummy entry + * which has pucStartAddress set to NULL. It will initialize the heap allocator to serve memory + * from these ranges. + * + * @param pxHeapRegions Array of region definitions + */ void vPortDefineHeapRegionsTagged( const HeapRegionTagged_t * const pxHeapRegions ); + + +/** + * @brief Allocate memory from a region with a certain tag + * + * Like pvPortMalloc, this returns an allocated chunk of memory. This function, + * however, forces the allocator to allocate from a region specified by a + * specific tag. + * + * @param xWantedSize Size needed, in bytes + * @param tag Tag of the memory region the allocation has to be from + * + * @return Pointer to allocated memory if succesful. + * NULL if unsuccesful. + */ void *pvPortMallocTagged( size_t xWantedSize, BaseType_t tag ); + +/** + * @brief Get the lowest amount of memory free for a certain tag + * + * This function allows the user to see what the least amount of + * free memory for a certain tag is. + * + * @param tag Tag of the memory region + * + * @return Minimum amount of free bytes available in the runtime of + * the program + */ size_t xPortGetMinimumEverFreeHeapSizeTagged( BaseType_t tag ); + +/** + * @brief Get the amount of free bytes in a certain tagged region + * + * Works like xPortGetFreeHeapSize but allows the user to specify + * a specific tag + * + * @param tag Tag of the memory region + * + * @return Remaining amount of free bytes in region + */ size_t xPortGetFreeHeapSizeTagged( BaseType_t tag ); diff --git a/docs/Doxyfile b/docs/Doxyfile index bdb91a4dc..2456b6c2e 100755 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -28,7 +28,9 @@ INPUT = ../components/esp32/include/esp_wifi.h \ ../components/app_update/include/esp_ota_ops.h \ ../components/ethernet/include/esp_eth.h \ ../components/ulp/include/esp32/ulp.h \ - ../components/esp32/include/esp_intr_alloc.h + ../components/esp32/include/esp_intr_alloc.h \ + ../components/esp32/include/esp_heap_alloc_caps.h \ + ../components/freertos/include/freertos/heap_regions.h ## Get warnings for functions that have no documentation for their parameters or return value ## diff --git a/docs/api/mem_alloc.rst b/docs/api/mem_alloc.rst new file mode 100644 index 000000000..d2af7f287 --- /dev/null +++ b/docs/api/mem_alloc.rst @@ -0,0 +1,78 @@ +Memory allocation +==================== + +Overview +-------- + +The ESP32 has multiple types of RAM. Internally, there's IRAM, DRAM as well as RAM that can be used as both. It's also +possible to connect external SPI flash to the ESP32; it's memory can be integrated into the ESP32s memory map using +the flash cache. + +In order to make use of all this memory, esp-idf has a capabilities-based memory allocator. Basically, if you want to have +memory with certain properties (for example, DMA-capable, accessible by a certain PID, or capable of executing code), you +can create an OR-mask of the required capabilities and pass that to pvPortMallocCaps. For instance, the normal malloc +code internally allocates memory with ```pvPortMallocCaps(size, MALLOC_CAP_8BIT)``` in order to get data memory that is +byte-addressable. + +Internally, this allocator is split in two pieces. The allocator in the FreeRTOS directory can allocate memory from +tagged regions: a tag is an integer value and every region of free memory has one of these tags. The esp32-specific +code initializes these regions with specific tags, and contains the logic to select applicable tags from the +capabilities given by the user. While shown in the public API, tags are used in the communication between the two parts +and should not be used directly. + +Special Uses +------------ + +If a certain memory structure is only addressed in 32-bit units, for example an array of ints or pointers, it can be +useful to allocate it with the MALLOC_CAP_32BIT flag. This also allows the allocator to give out IRAM memory; something +which it can't do for a normal malloc() call. This can help to use all the available memory in the ESP32. + + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * `esp_heap_alloc_caps.h `_ + * `heap_regions.h `_ + + +Macros +^^^^^^ + +.. doxygendefine:: MALLOC_CAP_EXEC +.. doxygendefine:: MALLOC_CAP_32BIT +.. doxygendefine:: MALLOC_CAP_8BIT +.. doxygendefine:: MALLOC_CAP_DMA +.. doxygendefine:: MALLOC_CAP_PID2 +.. doxygendefine:: MALLOC_CAP_PID3 +.. doxygendefine:: MALLOC_CAP_PID4 +.. doxygendefine:: MALLOC_CAP_PID5 +.. doxygendefine:: MALLOC_CAP_PID6 +.. doxygendefine:: MALLOC_CAP_PID7 +.. doxygendefine:: MALLOC_CAP_SPISRAM +.. doxygendefine:: MALLOC_CAP_INVALID + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygentypedef:: HeapRegionTagged_t + +Enumerations +^^^^^^^^^^^^ + +Structures +^^^^^^^^^^ + +Functions +^^^^^^^^^ + +.. doxygenfunction:: heap_alloc_caps_init +.. doxygenfunction:: pvPortMallocCaps +.. doxygenfunction:: xPortGetFreeHeapSizeCaps +.. doxygenfunction:: xPortGetMinimumEverFreeHeapSizeCaps +.. doxygenfunction:: vPortDefineHeapRegionsTagged +.. doxygenfunction:: pvPortMallocTagged +.. doxygenfunction:: xPortGetMinimumEverFreeHeapSizeTagged +.. doxygenfunction:: xPortGetFreeHeapSizeTagged diff --git a/docs/index.rst b/docs/index.rst index 4e58cfe02..8a42e762c 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -48,7 +48,8 @@ Contents: 1.3. Flash encryption and secure boot: how they work and APIs 1.4. Lower Power Coprocessor - TBA 1.5. Watchdogs - 1.6. ... + 1.6. Memory allocation + 1.7. ... 2. Memory - TBA 2.1. Memory layout of the application (IRAM/IROM, limitations of each) - TBA 2.2. Flash layout and partitions - TBA @@ -111,6 +112,7 @@ Contents: Virtual Filesystem Ethernet Interrupt Allocation + Memory Allocation deep-sleep-stub Template From 6f0a494cae81761c6d9d558de01a8b1d7dfea369 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Tue, 13 Dec 2016 22:21:20 +0800 Subject: [PATCH 6/7] Add testcase, fix executable memory allocated in shared dram/iram region --- components/esp32/heap_alloc_caps.c | 109 ++++++++++++++---- components/esp32/test/test_malloc_caps.c | 64 ++++++++++ components/freertos/heap_regions.c | 2 +- .../freertos/include/freertos/heap_regions.h | 9 ++ docs/api/mem_alloc.rst | 9 +- tools/unit-test-app/sdkconfig | 3 + 6 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 components/esp32/test/test_malloc_caps.c diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index 511903c43..a77d372b4 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -18,6 +18,7 @@ #include "esp_heap_alloc_caps.h" #include "spiram.h" #include "esp_log.h" +#include static const char* TAG = "heap_alloc_caps"; @@ -38,6 +39,7 @@ hardwiring addresses. typedef struct { const char *name; uint32_t prio[NO_PRIOS]; + bool aliasedIram; } tag_desc_t; /* @@ -46,23 +48,23 @@ Each tag contains NO_PRIOS entries; later entries are only taken if earlier ones Make sure there are never more than HEAPREGIONS_MAX_TAGCOUNT (in heap_regions.h) tags (ex the last empty marker) */ static const tag_desc_t tag_desc[]={ - { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }}, //Tag 0: Plain ole D-port RAM - { "D/IRAM", { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }}, //Tag 1: Plain ole D-port RAM which has an alias on the I-port - { "IRAM", { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }}, //Tag 2: IRAM - { "PID2IRAM", { MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, //Tag 3-8: PID 2-7 IRAM - { "PID3IRAM", { MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // - { "PID4IRAM", { MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // - { "PID5IRAM", { MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // - { "PID6IRAM", { MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // - { "PID7IRAM", { MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }}, // - { "PID2DRAM", { MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, //Tag 9-14: PID 2-7 DRAM - { "PID3DRAM", { MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // - { "PID4DRAM", { MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // - { "PID5DRAM", { MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // - { "PID6DRAM", { MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // - { "PID7DRAM", { MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }}, // - { "SPISRAM", { MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}}, //Tag 15: SPI SRAM data - { "", { MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID }} //End + { "DRAM", { MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT, 0 }, false}, //Tag 0: Plain ole D-port RAM + { "D/IRAM", { 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC }, true}, //Tag 1: Plain ole D-port RAM which has an alias on the I-port + { "IRAM", { MALLOC_CAP_EXEC|MALLOC_CAP_32BIT, 0, 0 }, false}, //Tag 2: IRAM + { "PID2IRAM", { MALLOC_CAP_PID2, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, //Tag 3-8: PID 2-7 IRAM + { "PID3IRAM", { MALLOC_CAP_PID3, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, // + { "PID4IRAM", { MALLOC_CAP_PID4, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, // + { "PID5IRAM", { MALLOC_CAP_PID5, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, // + { "PID6IRAM", { MALLOC_CAP_PID6, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, // + { "PID7IRAM", { MALLOC_CAP_PID7, 0, MALLOC_CAP_EXEC|MALLOC_CAP_32BIT }, false}, // + { "PID2DRAM", { MALLOC_CAP_PID2, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, //Tag 9-14: PID 2-7 DRAM + { "PID3DRAM", { MALLOC_CAP_PID3, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, // + { "PID4DRAM", { MALLOC_CAP_PID4, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, // + { "PID5DRAM", { MALLOC_CAP_PID5, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, // + { "PID6DRAM", { MALLOC_CAP_PID6, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, // + { "PID7DRAM", { MALLOC_CAP_PID7, MALLOC_CAP_8BIT, MALLOC_CAP_32BIT }, false}, // + { "SPISRAM", { MALLOC_CAP_SPISRAM, 0, MALLOC_CAP_DMA|MALLOC_CAP_8BIT|MALLOC_CAP_32BIT}, false}, //Tag 15: SPI SRAM data + { "", { MALLOC_CAP_INVALID, MALLOC_CAP_INVALID, MALLOC_CAP_INVALID }, false} //End }; /* @@ -231,14 +233,61 @@ void heap_alloc_caps_init() { vPortDefineHeapRegionsTagged( regions ); } +//First and last words of the D/IRAM region, for both the DRAM address as well as the IRAM alias. +#define DIRAM_IRAM_START 0x400A0000 +#define DIRAM_IRAM_END 0x400BFFFC +#define DIRAM_DRAM_START 0x3FFE0000 +#define DIRAM_DRAM_END 0x3FFFFFFC + /* -Standard malloc() implementation. Will return ho-hum byte-accessible data memory. + This takes a memory chunk in a region that can be addressed as both DRAM as well as IRAM. It will convert it to + IRAM in such a way that it can be later freed. It assumes both the address as wel as the length to be word-aligned. + It returns a region that's 1 word smaller than the region given because it stores the original Dram address there. + + In theory, we can also make this work by prepending a struct that looks similar to the block link struct used by the + heap allocator itself, which will allow inspection tools relying on any block returned from any sort of malloc to + have such a block in front of it, work. We may do this later, if/when there is demand for it. For now, a simple + pointer is used. +*/ +void *dram_alloc_to_iram_addr(void *addr, size_t len) +{ + uint32_t dstart=(int)addr; //First word + uint32_t dend=((int)addr)+len-4; //Last word + configASSERT(dstart>=DIRAM_DRAM_START); + configASSERT(dend<=DIRAM_DRAM_END); + configASSERT((dstart&3)==0); + configASSERT((dend&3)==0); + uint32_t istart=DIRAM_IRAM_START+(DIRAM_DRAM_END-dend); + uint32_t *iptr=(uint32_t*)istart; + *iptr=dstart; + return (void*)(iptr+1); +} + +/* +Standard malloc() implementation. Will return standard no-frills byte-accessible data memory. */ void *pvPortMalloc( size_t xWantedSize ) { return pvPortMallocCaps( xWantedSize, MALLOC_CAP_8BIT ); } +/* + Standard free() implementation. Will pass memory on to the allocator unless it's an IRAM address where the + actual meory is allocated in DRAM, it will convert to the DRAM address then. + */ +void vPortFree( void *pv ) +{ + if (((int)pv>=DIRAM_IRAM_START) && ((int)pv<=DIRAM_IRAM_END)) { + //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*)pv; + return vPortFreeTagged((void*)dramAddrPtr[-1]); + } + + return vPortFreeTagged(pv); +} + /* Routine to allocate a bit of memory with certain capabilities. caps is a bitfield of MALLOC_CAP_* bits. */ @@ -248,6 +297,17 @@ void *pvPortMallocCaps( size_t xWantedSize, uint32_t caps ) int tag, j; void *ret=NULL; uint32_t remCaps; + 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 tag_desc + //table would indicate there is a tag for this. + if ((caps & MALLOC_CAP_8BIT) || (caps & MALLOC_CAP_DMA)) { + return NULL; + } + //If any, EXEC memory should be 32-bit aligned, so round up to the next multiple of 4. + xWantedSize=(xWantedSize+3)&(~3); + } for (prio=0; prio +#include +#include "unity.h" +#include "rom/ets_sys.h" +#include "esp_heap_alloc_caps.h" +#include + + +TEST_CASE("Capabilities allocator test", "[esp32]") +{ + char *m1, *m2[10]; + int x; + size_t free8start, free32start, free8, free32; + free8start=xPortGetFreeHeapSizeCaps(MALLOC_CAP_8BIT); + free32start=xPortGetFreeHeapSizeCaps(MALLOC_CAP_32BIT); + printf("Free 8bit-capable memory: %dK, 32-bit capable memory %dK\n", free8start, free32start); + TEST_ASSERT(free32start>free8start); + printf("Allocating 10K of 8-bit capable RAM\n"); + m1=pvPortMallocCaps(10*1024, MALLOC_CAP_8BIT); + printf("--> %p\n", m1); + free8=xPortGetFreeHeapSizeCaps(MALLOC_CAP_8BIT); + free32=xPortGetFreeHeapSizeCaps(MALLOC_CAP_32BIT); + printf("Free 8bit-capable memory: %dK, 32-bit capable memory %dK\n", free8, free32); + //Both should have gone down by 10K; 8bit capable ram is also 32-bit capable + TEST_ASSERT(free8<(free8start-10*1024)); + TEST_ASSERT(free32<(free32start-10*1024)); + //Assume we got DRAM back + TEST_ASSERT((((int)m1)&0xFF000000)==0x3F000000); + free(m1); + printf("Freeing; allocating 10K of 32K-capable RAM\n"); + m1=pvPortMallocCaps(10*1024, MALLOC_CAP_32BIT); + printf("--> %p\n", m1); + free8=xPortGetFreeHeapSizeCaps(MALLOC_CAP_8BIT); + free32=xPortGetFreeHeapSizeCaps(MALLOC_CAP_32BIT); + printf("Free 8bit-capable memory: %dK, 32-bit capable memory %dK\n", free8, free32); + //Only 32-bit should have gone down by 10K: 32-bit isn't necessarily 8bit capable + TEST_ASSERT(free32<(free32start-10*1024)); + TEST_ASSERT(free8==free8start); + //Assume we got IRAM back + TEST_ASSERT((((int)m1)&0xFF000000)==0x40000000); + free(m1); + printf("Allocating impossible caps\n"); + m1=pvPortMallocCaps(10*1024, MALLOC_CAP_8BIT|MALLOC_CAP_EXEC); + printf("--> %p\n", m1); + TEST_ASSERT(m1==NULL); + printf("Testing changeover iram -> dram"); + for (x=0; x<10; x++) { + m2[x]=pvPortMallocCaps(10*1024, MALLOC_CAP_32BIT); + printf("--> %p\n", m2[x]); + } + TEST_ASSERT((((int)m2[0])&0xFF000000)==0x40000000); + TEST_ASSERT((((int)m2[9])&0xFF000000)==0x3F000000); + printf("Test if allocating executable code still gives IRAM, even with dedicated IRAM region depleted\n"); + m1=pvPortMallocCaps(10*1024, MALLOC_CAP_EXEC); + printf("--> %p\n", m1); + TEST_ASSERT((((int)m1)&0xFF000000)==0x40000000); + free(m1); + for (x=0; x<10; x++) free(m2[x]); + printf("Done.\n"); +} diff --git a/components/freertos/heap_regions.c b/components/freertos/heap_regions.c index 5ff1f2817..a7c960603 100644 --- a/components/freertos/heap_regions.c +++ b/components/freertos/heap_regions.c @@ -341,7 +341,7 @@ void *pvReturn = NULL; } /*-----------------------------------------------------------*/ -void vPortFree( void *pv ) +void vPortFreeTagged( void *pv ) { uint8_t *puc = ( uint8_t * ) pv; BlockLink_t *pxLink; diff --git a/components/freertos/include/freertos/heap_regions.h b/components/freertos/include/freertos/heap_regions.h index 30d0dcb39..090c5b9b3 100644 --- a/components/freertos/include/freertos/heap_regions.h +++ b/components/freertos/include/freertos/heap_regions.h @@ -58,6 +58,15 @@ void vPortDefineHeapRegionsTagged( const HeapRegionTagged_t * const pxHeapRegion */ void *pvPortMallocTagged( size_t xWantedSize, BaseType_t tag ); +/** + * @brief Free memory allocated with pvPortMallocTagged + * + * This is basically an implementation of free(). + * + * @param pv Pointer to region allocated by pvPortMallocTagged + */ +void vPortFreeTagged( void *pv ); + /** * @brief Get the lowest amount of memory free for a certain tag * diff --git a/docs/api/mem_alloc.rst b/docs/api/mem_alloc.rst index d2af7f287..cebea5b8a 100644 --- a/docs/api/mem_alloc.rst +++ b/docs/api/mem_alloc.rst @@ -14,6 +14,9 @@ can create an OR-mask of the required capabilities and pass that to pvPortMalloc code internally allocates memory with ```pvPortMallocCaps(size, MALLOC_CAP_8BIT)``` in order to get data memory that is byte-addressable. +Because malloc uses this allocation system as well, memory allocated using pvPortMallocCaps can be freed by calling +the standard ```free()``` function. + Internally, this allocator is split in two pieces. The allocator in the FreeRTOS directory can allocate memory from tagged regions: a tag is an integer value and every region of free memory has one of these tags. The esp32-specific code initializes these regions with specific tags, and contains the logic to select applicable tags from the @@ -59,11 +62,6 @@ Type Definitions .. doxygentypedef:: HeapRegionTagged_t -Enumerations -^^^^^^^^^^^^ - -Structures -^^^^^^^^^^ Functions ^^^^^^^^^ @@ -74,5 +72,6 @@ Functions .. doxygenfunction:: xPortGetMinimumEverFreeHeapSizeCaps .. doxygenfunction:: vPortDefineHeapRegionsTagged .. doxygenfunction:: pvPortMallocTagged +.. doxygenfunction:: vPortFreeTagged .. doxygenfunction:: xPortGetMinimumEverFreeHeapSizeTagged .. doxygenfunction:: xPortGetFreeHeapSizeTagged diff --git a/tools/unit-test-app/sdkconfig b/tools/unit-test-app/sdkconfig index 1b9db9951..14b31e0d1 100644 --- a/tools/unit-test-app/sdkconfig +++ b/tools/unit-test-app/sdkconfig @@ -93,6 +93,7 @@ CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048 CONFIG_MAIN_TASK_STACK_SIZE=4096 CONFIG_NEWLIB_STDOUT_ADDCR=y +# CONFIG_NEWLIB_NANO_FORMAT is not set CONFIG_CONSOLE_UART_DEFAULT=y # CONFIG_CONSOLE_UART_CUSTOM is not set # CONFIG_CONSOLE_UART_NONE is not set @@ -171,6 +172,8 @@ CONFIG_MBEDTLS_HARDWARE_AES=y CONFIG_MBEDTLS_HARDWARE_MPI=y CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y CONFIG_MBEDTLS_HARDWARE_SHA=y +CONFIG_MBEDTLS_HAVE_TIME=y +# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set # # SPI Flash driver From 712f53176dda462b0d3d44caebba6d6458fe4ee4 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 14 Dec 2016 11:44:17 +0800 Subject: [PATCH 7/7] Make internal function static --- components/esp32/heap_alloc_caps.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/components/esp32/heap_alloc_caps.c b/components/esp32/heap_alloc_caps.c index a77d372b4..7bb3b4087 100644 --- a/components/esp32/heap_alloc_caps.c +++ b/components/esp32/heap_alloc_caps.c @@ -249,7 +249,7 @@ void heap_alloc_caps_init() { have such a block in front of it, work. We may do this later, if/when there is demand for it. For now, a simple pointer is used. */ -void *dram_alloc_to_iram_addr(void *addr, size_t len) +static void *dram_alloc_to_iram_addr(void *addr, size_t len) { uint32_t dstart=(int)addr; //First word uint32_t dend=((int)addr)+len-4; //Last word @@ -385,8 +385,3 @@ size_t xPortGetMinimumEverFreeHeapSize( void ) } - - - - -