diff --git a/include/FreeRTOS.h b/include/FreeRTOS.h index 3fecbdd..b597ed9 100644 --- a/include/FreeRTOS.h +++ b/include/FreeRTOS.h @@ -2670,6 +2670,10 @@ #if ( configGENERATE_RUN_TIME_STATS == 1 ) + #ifndef configUSE_STATS_FORMATTING_FUNCTIONS + #define configUSE_STATS_FORMATTING_FUNCTIONS 1 + #endif + #ifndef portCONFIGURE_TIMER_FOR_RUN_TIME_STATS #error If configGENERATE_RUN_TIME_STATS is defined then portCONFIGURE_TIMER_FOR_RUN_TIME_STATS must also be defined. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS should call a port layer function to setup a peripheral timer/counter that can then be used as the run time counter time base. #endif /* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS */ diff --git a/include/task.h b/include/task.h index 0414eb9..73b1657 100644 --- a/include/task.h +++ b/include/task.h @@ -169,6 +169,9 @@ typedef struct xTASK_STATUS UBaseType_t uxCurrentPriority; /* The priority at which the task was running (may be inherited) when the structure was populated. */ UBaseType_t uxBasePriority; /* The priority to which the task will return if the task's current priority has been inherited to avoid unbounded priority inversion when obtaining a mutex. Only valid if configUSE_MUTEXES is defined as 1 in FreeRTOSConfig.h. */ configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /* The total run time allocated to the task so far, as defined by the run time stats clock. See https://www.FreeRTOS.org/rtos-run-time-stats.html. Only valid when configGENERATE_RUN_TIME_STATS is defined as 1 in FreeRTOSConfig.h. */ +#if ( configGENERATE_RUN_TIME_STATS == 1 ) + uint32_t ulPeriodDeltaRunTime; /* Runtime counter delta within the sampling period */ +#endif StackType_t * pxStackBase; /* Points to the lowest address of the task's stack area. */ #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) StackType_t * pxTopOfStack; /* Points to the top address of the task's stack area. */ @@ -3769,6 +3772,15 @@ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNC #endif /* #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) && ( configENABLE_ACCESS_CONTROL_LIST == 1 ) ) */ +#if ( configSUPPORT_CMBACKTRACE == 1 ) + /* Functions to support CmBacktrace */ + void* vTaskGetCurrentTCB( void ); + uint32_t* vTaskStackAddr( void ); + volatile uint32_t* vTaskStackTOPAddr( void ); + uint32_t vTaskStackSize( void ); + char* vTaskName( void ); +#endif + /* *INDENT-OFF* */ #ifdef __cplusplus } diff --git a/portable/MemMang/heap_5.c b/portable/MemMang/heap_5.c index 4e872f6..eae4f2f 100644 --- a/portable/MemMang/heap_5.c +++ b/portable/MemMang/heap_5.c @@ -78,6 +78,12 @@ #include "FreeRTOS.h" #include "task.h" +#include "platform_opts.h" + + +#if defined(CONFIG_PLATFORM_8195A) || defined(CONFIG_PLATFORM_8711B) +#include "section_config.h" +#endif #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE @@ -184,6 +190,12 @@ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEG /*-----------------------------------------------------------*/ +/* Platform-specific definitions */ +#if defined(CONFIG_PLATFORM_8195A) +#define SRAM_START_ADDRESS 0x10000000 +#define SDRAM_START_ADDRESS 0x30000000 +#endif + /* The size of the structure placed at the beginning of each allocated memory * block must by correctly byte aligned. */ static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ); @@ -198,6 +210,10 @@ PRIVILEGED_DATA static size_t xFreeBytesRemaining = ( size_t ) 0U; PRIVILEGED_DATA static size_t xMinimumEverFreeBytesRemaining = ( size_t ) 0U; PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = ( size_t ) 0U; PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = ( size_t ) 0U; +#if defined(CONFIG_PLATFORM_8195A) +PRIVILEGED_DATA static size_t xSRAMFreeBytesRemaining = ( size_t ) 0U; +PRIVILEGED_DATA static size_t xSDRAMFreeBytesRemaining = ( size_t ) 0U; +#endif #if ( configENABLE_HEAP_PROTECTOR == 1 ) @@ -212,8 +228,67 @@ PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = ( size_t ) 0U; /*-----------------------------------------------------------*/ +/* External memory management support */ +static void (*ext_free)(void *p) = NULL; +static uint32_t ext_upper = 0; +static uint32_t ext_lower = 0; + +/* Platform-specific heap definitions */ +#if defined(CONFIG_PLATFORM_8195A) || defined(CONFIG_PLATFORM_8711B) +SRAM_BF_DATA_SECTION static uint8_t ucHeap[configTOTAL_HEAP_SIZE]; + +#if defined(CONFIG_PLATFORM_8195A) +HeapRegion_t xHeapRegions[] = { + { (uint8_t*)0x10002300, 0x3D00 }, /* Image1 recycle heap */ + { ucHeap, sizeof(ucHeap) }, /* Main heap */ + { NULL, 0 } /* Terminator */ +}; +#elif defined(CONFIG_PLATFORM_8711B) +#include "rtl8710b_boot.h" +extern BOOT_EXPORT_SYMB_TABLE boot_export_symbol; + +HeapRegion_t xHeapRegions[] = { + { 0, 0 }, /* Image1 reserved */ + { ucHeap, sizeof(ucHeap) }, /* Main heap */ + { 0, 0 }, /* RDP reserved */ + { NULL, 0 } /* Terminator */ +}; +#endif +#endif + +/* Debug support function */ +#if configENABLE_HEAP_DEBUG +void vPortDumpMemBlockList(void) { + BlockLink_t *pxBlock = &xStart; + int count = 0; + + configPRINTF(("Memory Block List:\n")); + while(pxBlock->pxNextFreeBlock != NULL) { + configPRINTF(("[%d]=0x%p, %d\n", count++, pxBlock, pxBlock->xBlockSize)); + pxBlock = pxBlock->pxNextFreeBlock; + } +} +#endif + +/* Modified pvPortMalloc */ void * pvPortMalloc( size_t xWantedSize ) { + /* Initialize heap regions if needed */ + #if defined(CONFIG_PLATFORM_8711B) + if(pxEnd == NULL) { + /* Configure platform-specific regions */ + xHeapRegions[0].xSizeInBytes = (uint32_t)((uint8_t*)0x10005000 - (uint8_t*)boot_export_symbol.boot_ram_end); + xHeapRegions[0].pucStartAddress = (uint8_t*)boot_export_symbol.boot_ram_end; + + if(!IsRDPenabled()) { + xHeapRegions[2].xSizeInBytes = 0x1000; + xHeapRegions[2].pucStartAddress = (uint8_t*)0x1003f000; + } + + vPortDefineHeapRegions(xHeapRegions); + } + #endif + BlockLink_t * pxBlock; BlockLink_t * pxPreviousBlock; BlockLink_t * pxNewBlockLink; @@ -328,7 +403,14 @@ void * pvPortMalloc( size_t xWantedSize ) } xFreeBytesRemaining -= pxBlock->xBlockSize; - + #if defined(CONFIG_PLATFORM_8195A) + /* Update region-specific statistics */ + if(((uint32_t)pxBlock >= SRAM_START_ADDRESS) && ((uint32_t)pxBlock < SDRAM_START_ADDRESS)) { + xSRAMFreeBytesRemaining -= pxBlock->xBlockSize; + } else if((uint32_t)pxBlock >= SDRAM_START_ADDRESS) { + xSDRAMFreeBytesRemaining -= pxBlock->xBlockSize; + } + #endif if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining ) { xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; @@ -386,7 +468,7 @@ void * pvPortMalloc( size_t xWantedSize ) } /*-----------------------------------------------------------*/ -void vPortFree( void * pv ) +void __vPortFree( void * pv ) { uint8_t * puc = ( uint8_t * ) pv; BlockLink_t * pxLink; @@ -426,6 +508,12 @@ void vPortFree( void * pv ) { /* Add this block to the list of free blocks. */ xFreeBytesRemaining += pxLink->xBlockSize; + #if defined CONFIG_PLATFORM_8195A + if(((uint32_t) pxLink >= SRAM_START_ADDRESS) && ((uint32_t) pxLink < SDRAM_START_ADDRESS)) + xSRAMFreeBytesRemaining += pxLink->xBlockSize; + else if((uint32_t) pxLink >= SDRAM_START_ADDRESS) + xSDRAMFreeBytesRemaining += pxLink->xBlockSize; + #endif traceFREE( pv, pxLink->xBlockSize ); prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); xNumberOfSuccessfulFrees++; @@ -443,12 +531,41 @@ void vPortFree( void * pv ) } } } + +/* Modified vPortFree with external free support */ +void vPortFree(void *pv) { + if(((uint32_t)pv >= ext_lower) && ((uint32_t)pv < ext_upper)) { + if(ext_free) ext_free(pv); + return; + } + + /* Original vPortFree implementation */ + __vPortFree(pv); +} + +void vPortSetExtFree(void (*free)(void *p), uint32_t upper, uint32_t lower) { + ext_free = free; + ext_upper = upper; + ext_lower = lower; +} + /*-----------------------------------------------------------*/ size_t xPortGetFreeHeapSize( void ) { return xFreeBytesRemaining; } + +#if defined(CONFIG_PLATFORM_8195A) +size_t xPortGetSRAMFreeHeapSize(void) { + return xSRAMFreeBytesRemaining; +} + +size_t xPortGetSDRAMFreeHeapSize(void) { + return xSDRAMFreeBytesRemaining; +} +#endif + /*-----------------------------------------------------------*/ size_t xPortGetMinimumEverFreeHeapSize( void ) @@ -556,6 +673,9 @@ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) /* PRIVI BlockLink_t * pxPreviousFreeBlock; portPOINTER_SIZE_TYPE xAlignedHeap; size_t xTotalRegionSize, xTotalHeapSize = 0; + #if defined CONFIG_PLATFORM_8195A + size_t xSRAMTotalHeapSize = 0, xSDRAMTotalHeapSize = 0; + #endif BaseType_t xDefinedRegions = 0; portPOINTER_SIZE_TYPE xAddress; const HeapRegion_t * pxHeapRegion; @@ -646,6 +766,13 @@ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) /* PRIVI xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; + #if defined CONFIG_PLATFORM_8195A + if(((uint32_t) pxFirstFreeBlockInRegion >= SRAM_START_ADDRESS) && ((uint32_t) pxFirstFreeBlockInRegion < SDRAM_START_ADDRESS)) + xSRAMTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; + else if((uint32_t) pxFirstFreeBlockInRegion >= SDRAM_START_ADDRESS) + xSDRAMTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize; + #endif + #if ( configENABLE_HEAP_PROTECTOR == 1 ) { if( ( pucHeapHighAddress == NULL ) || @@ -663,6 +790,10 @@ void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) /* PRIVI xMinimumEverFreeBytesRemaining = xTotalHeapSize; xFreeBytesRemaining = xTotalHeapSize; + #if defined CONFIG_PLATFORM_8195A + xSRAMFreeBytesRemaining = xSRAMTotalHeapSize; + xSDRAMFreeBytesRemaining = xSDRAMTotalHeapSize; + #endif /* Check something was actually defined before it is accessed. */ configASSERT( xTotalHeapSize ); @@ -747,3 +878,73 @@ void vPortHeapResetState( void ) #endif /* #if ( configENABLE_HEAP_PROTECTOR == 1 ) */ } /*-----------------------------------------------------------*/ +/* + * Reallocates a memory block to a new size while preserving its contents. + * + * @param pv Pointer to existing memory block, or NULL for new allocation + * @param xWantedSize Desired size in bytes, or 0 to free the memory + * @return Pointer to new memory block, or NULL if allocation failed + */ +void* pvPortReAlloc(void *pv, size_t xWantedSize) { + // handle external memory region if applicable + if (pv && ((uint32_t)pv >= ext_lower) && ((uint32_t)pv < ext_upper)) { + if (ext_free) { + ext_free(pv); + } + pv = NULL; + } + + // handle NULL pointer with wanted size (simple malloc) + if (!pv && xWantedSize) { + return pvPortMalloc(xWantedSize); + } + + // handle zero size (simple free) + if (xWantedSize == 0) { + vPortFree(pv); + return NULL; + } + + // at this point, we have a valid pointer and non-zero wanted size + BlockLink_t *pxLink; + unsigned char *puc = (unsigned char *)pv; + + puc -= xHeapStructSize; + pxLink = (BlockLink_t *)puc; + size_t oldSize = (pxLink->xBlockSize & ~heapBLOCK_ALLOCATED_BITMASK) - xHeapStructSize; + + if (xWantedSize <= oldSize) { + // TODO: could potentially split the block here if difference is significant + return pv; + } + + // allocate new block + void *newArea = pvPortMalloc(xWantedSize); + if (!newArea) { + return NULL; + } + + memcpy(newArea, pv, oldSize); + + vTaskSuspendAll(); + { + // mark block as free and update free bytes counter + heapFREE_BLOCK(pxLink); + xFreeBytesRemaining += pxLink->xBlockSize; + + #if defined CONFIG_PLATFORM_8195A + if (((uint32_t)pxLink >= SRAM_START_ADDRESS) && ((uint32_t)pxLink < SDRAM_START_ADDRESS)) { + xSRAMFreeBytesRemaining += pxLink->xBlockSize; + } else if ((uint32_t)pxLink >= SDRAM_START_ADDRESS) { + xSDRAMFreeBytesRemaining += pxLink->xBlockSize; + } + #endif + + // insert freed block into free list + prvInsertBlockIntoFreeList(pxLink); + } + xTaskResumeAll(); + + return newArea; +} +/*-----------------------------------------------------------*/ diff --git a/tasks.c b/tasks.c index 22e11f0..1cb956f 100644 --- a/tasks.c +++ b/tasks.c @@ -383,6 +383,8 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) StackType_t * pxEndOfStack; /**< Points to the highest valid address for the stack. */ + #else + UBaseType_t uxSizeOfStack; /* Support For CmBacktrace */ #endif #if ( portCRITICAL_NESTING_IN_TCB == 1 ) @@ -409,6 +411,8 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to #if ( configGENERATE_RUN_TIME_STATS == 1 ) configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /**< Stores the amount of time the task has spent in the Running state. */ + configRUN_TIME_COUNTER_TYPE ulStartRunTimeCounterOfPeriod; + configRUN_TIME_COUNTER_TYPE ulEndRunTimeCounterOfPeriod; #endif #if ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) @@ -522,6 +526,21 @@ PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime[ conf #endif +/* + * Defines the size, in words, of the stack allocated to the idle task. + */ +#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE + +#define RTL_PLACE_IDLE_STACK_IN_SRAM +#ifdef RTL_PLACE_IDLE_STACK_IN_SRAM + /* Place idle stack in SRAM to prevent hangs when SDRAM is suspended */ + #if ((defined CONFIG_PLATFORM_8195A) || (defined CONFIG_PLATFORM_8711B)) + #include "section_config.h" + SRAM_BF_DATA_SECTION + #endif + static unsigned char ucIdleTaskHeap[ tskIDLE_STACK_SIZE * sizeof( StackType_t ) ]; +#endif + /*-----------------------------------------------------------*/ /* File private functions. --------------------------------*/ @@ -4944,6 +4963,10 @@ BaseType_t xTaskIncrementTick( void ) #endif } + #if ( configGENERATE_RUN_TIME_STATS == 1 ) + prvGetRunTimeStatsOfPeriodForTasksInList(xTickCount); + #endif + traceRETURN_xTaskIncrementTick( xSwitchRequired ); return xSwitchRequired; @@ -6929,6 +6952,30 @@ static void prvResetNextTaskUnblockTime( void ) #endif /* configUSE_MUTEXES */ /*-----------------------------------------------------------*/ +void* vTaskGetCurrentTCB(void) { + return (void*)pxCurrentTCB; +} +/*-----------------------------------------------------------*/ +uint32_t* vTaskStackAddr(void) { + return pxCurrentTCB->pxStack; +} +/*-----------------------------------------------------------*/ +volatile uint32_t* vTaskStackTOPAddr(void) { + return pxCurrentTCB->pxTopOfStack; +} +/*-----------------------------------------------------------*/ +uint32_t vTaskStackSize(void) { + #if ( portSTACK_GROWTH > 0 ) + return (pxNewTCB->pxEndOfStack - pxNewTCB->pxStack + 1); + #else + return pxCurrentTCB->uxSizeOfStack; + #endif +} +/*-----------------------------------------------------------*/ +char* vTaskName(void) { + return pxCurrentTCB->pcTaskName; +} + #if ( configNUMBER_OF_CORES > 1 ) /* If not in a critical section then yield immediately. @@ -7602,6 +7649,52 @@ static void prvResetNextTaskUnblockTime( void ) #endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */ /*-----------------------------------------------------------*/ +#if ( configGENERATE_RUN_TIME_STATS == 1 ) +static void prvGetRunTimeStatsOfPeriodForTasksInList(portTickType tickTmp) { + if (tickTmp % portCONFIGURE_STATS_PERIOD_VALUE) { + return; + } + + // Iterate through task lists and collect stats + for (UBaseType_t uxQueue = configMAX_PRIORITIES; uxQueue > 0; uxQueue--) { + if (!listLIST_IS_EMPTY(&(pxReadyTasksLists[uxQueue-1]))) { + prvGenerateRunTimeOfPeriod(&(pxReadyTasksLists[uxQueue-1]), tickTmp); + } + } + + // Check delayed and suspended lists + if (!listLIST_IS_EMPTY(pxDelayedTaskList)) { + prvGenerateRunTimeOfPeriod(pxDelayedTaskList, tickTmp); + } + + if (!listLIST_IS_EMPTY(pxOverflowDelayedTaskList)) { + prvGenerateRunTimeOfPeriod(pxOverflowDelayedTaskList, tickTmp); + } + + #if ( INCLUDE_vTaskSuspend == 1 ) + if (!listLIST_IS_EMPTY(&xSuspendedTaskList)) { + prvGenerateRunTimeOfPeriod(&xSuspendedTaskList, tickTmp); + } + #endif +} + +static void prvGenerateRunTimeOfPeriod(xList *pxList, portTickType tickTmp) { + volatile TCB_t *pxNextTCB, *pxFirstTCB; + + listGET_OWNER_OF_NEXT_ENTRY(pxFirstTCB, pxList); + do { + listGET_OWNER_OF_NEXT_ENTRY(pxNextTCB, pxList); + + if (tickTmp%(2*portCONFIGURE_STATS_PERIOD_VALUE)) { + pxNextTCB->ulStartRunTimeCounterOfPeriod = pxNextTCB->ulRunTimeCounter; + } else { + pxNextTCB->ulEndRunTimeCounterOfPeriod = pxNextTCB->ulRunTimeCounter; + } + + } while (pxNextTCB != pxFirstTCB); +} +#endif +/*-----------------------------------------------------------*/ TickType_t uxTaskResetEventItemValue( void ) {