Update source to Armbian-dev-202610.A311Y3

This commit is contained in:
2026-11-11 08:50:43 +08:00
parent 3428a94f6b
commit f459ef6a9e
12514 changed files with 2264376 additions and 468481 deletions
@@ -4,138 +4,163 @@
* SPDX-License-Identifier: MIT
*/
struct MemLeak {
size_t TaskNum;
size_t WantSize;
size_t FreeSize;
size_t WantTotalSize;
size_t FreeTotalSize;
size_t MallocCount;
size_t FreeCount;
TaskHandle_t xOwner;
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
/* Ensure CONFIG_DMALLOC_SIZE is defined externally or in config, e.g., #define CONFIG_DMALLOC_SIZE 32 */
struct MemLeak
{
uint8_t isUsed; /* Slot status: 1 - in use, 0 - free */
size_t TaskNum; /* Slot ID for display purpose */
size_t WantSize; /* Size of the last allocation */
size_t FreeSize; /* Size of the last free */
size_t WantTotalSize; /* Cumulative allocated total size */
size_t FreeTotalSize; /* Cumulative freed total size */
size_t MallocCount; /* Total allocation count */
size_t FreeCount; /* Total free count */
TaskHandle_t xOwner; /* Direct task handle matching */
};
struct MemLeak MemLeak_t[CONFIG_DMALLOC_SIZE];
/**
* @brief Get or allocate a free slot by matching the task handle directly
*/
static int prvGetOrAssignTaskSlot(TaskHandle_t xTask)
{
if (xTask == NULL)
return 0; // Default to slot 0 before the scheduler starts
// 1. Search existing slots using the task handle directly
for (int i = 1; i < CONFIG_DMALLOC_SIZE; i++)
{
if (MemLeak_t[i].isUsed && MemLeak_t[i].xOwner == xTask)
{
return i;
}
}
// 2. If not found, find a free slot
int assignedSlot = -1;
for (int i = 1; i < CONFIG_DMALLOC_SIZE; i++)
{
if (!MemLeak_t[i].isUsed)
{
memset(&MemLeak_t[i], 0, sizeof(struct MemLeak));
MemLeak_t[i].isUsed = 1;
MemLeak_t[i].TaskNum = i;
MemLeak_t[i].xOwner = xTask;
assignedSlot = i;
break;
}
}
return assignedSlot;
}
/**
* @brief Record memory allocation
*/
void vdRecordMalloc(size_t xWantedSize)
{
size_t MemTaskNum;
TaskHandle_t taskTempHandle;
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
MemLeak_t[0].TaskNum = 0;
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED)
{
MemLeak_t[0].WantSize = xWantedSize;
MemLeak_t[0].WantTotalSize += xWantedSize;
MemLeak_t[0].MallocCount++;
MemLeak_t[0].xOwner = NULL;
} else {
taskTempHandle = xTaskGetCurrentTaskHandle();
MemTaskNum = uxTaskGetTaskNumber(taskTempHandle);
MemLeak_t[MemTaskNum].TaskNum = MemTaskNum;
MemLeak_t[MemTaskNum].WantSize = xWantedSize;
MemLeak_t[MemTaskNum].WantTotalSize += xWantedSize;
MemLeak_t[MemTaskNum].MallocCount++;
MemLeak_t[0].xOwner = taskTempHandle;
return;
}
int idx = prvGetOrAssignTaskSlot(xTaskGetCurrentTaskHandle());
if (idx > 0 && idx < CONFIG_DMALLOC_SIZE)
{
MemLeak_t[idx].WantSize = xWantedSize;
MemLeak_t[idx].WantTotalSize += xWantedSize;
MemLeak_t[idx].MallocCount++;
}
}
/**
* @brief Record memory release
*/
void vdRecordFree(size_t xFreeSize)
{
size_t MemTaskNum;
TaskHandle_t taskTempHandle;
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
MemLeak_t[0].FreeCount++;
MemLeak_t[0].TaskNum = 0;
MemLeak_t[0].xOwner = NULL;
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED)
{
MemLeak_t[0].FreeSize = xFreeSize;
MemLeak_t[0].FreeTotalSize += xFreeSize;
} else {
taskTempHandle = xTaskGetCurrentTaskHandle();
MemTaskNum = uxTaskGetTaskNumber(taskTempHandle);
MemLeak_t[MemTaskNum].FreeCount++;
MemLeak_t[MemTaskNum].TaskNum = MemTaskNum;
MemLeak_t[MemTaskNum].xOwner = taskTempHandle;
MemLeak_t[MemTaskNum].FreeSize = xFreeSize;
MemLeak_t[MemTaskNum].FreeTotalSize += xFreeSize;
MemLeak_t[0].FreeCount++;
return;
}
int idx = prvGetOrAssignTaskSlot(xTaskGetCurrentTaskHandle());
if (idx > 0 && idx < CONFIG_DMALLOC_SIZE)
{
MemLeak_t[idx].FreeSize = xFreeSize;
MemLeak_t[idx].FreeTotalSize += xFreeSize;
MemLeak_t[idx].FreeCount++;
}
}
/**
* @brief Hook handler when a task is deleted: match handle, merge data, and free the slot
*/
void xClearSpecDmallocNode(void *xTask)
{
if (xTask == NULL)
{
return;
}
for (int i = 1; i < CONFIG_DMALLOC_SIZE; i++)
{
if (MemLeak_t[i].isUsed && MemLeak_t[i].xOwner == xTask)
{
MemLeak_t[0].WantTotalSize += MemLeak_t[i].WantTotalSize;
MemLeak_t[0].FreeTotalSize += MemLeak_t[i].FreeTotalSize;
MemLeak_t[0].MallocCount += MemLeak_t[i].MallocCount;
MemLeak_t[0].FreeCount += MemLeak_t[i].FreeCount;
memset(&MemLeak_t[i], 0, sizeof(struct MemLeak));
break;
}
}
}
/**
* @brief Print Dmalloc statistics using slot ID (tid).
* Pass 0 to print all active tasks and global slot, or pass a specific slot ID to query.
*/
int vPrintDmallocInfo(int tid)
{
int ret = 1, i;
printf("Taskname \tId\tLastmalloc\tLastfree\tTotalmalloc\tTotalfree\tMcount\tFcount\n");
printf(
"Taskname\tId\tLastmalloc\tLastfree\tTotalmalloc\tTotalfree\tMcount\tFcount\n");
#if defined(__aarch64__)
if (tid == 0) {
for (i = 0; i < CONFIG_DMALLOC_SIZE; i++) {
if (MemLeak_t[i].TaskNum) {
printf("%-8s\t%-4ld\t%-10ld\t%-8ld\t%-11ld\t%-9ld\t%-6ld\t%ld\n",
pcTaskGetName(MemLeak_t[i].xOwner),
MemLeak_t[i].TaskNum, MemLeak_t[i].WantSize,
MemLeak_t[i].FreeSize, MemLeak_t[i].WantTotalSize,
MemLeak_t[i].FreeTotalSize,
MemLeak_t[i].MallocCount, MemLeak_t[i].FreeCount);
}
if (i == 0) {
printf(
"None\t\t%-4ld\t%-10ld\t%-8ld\t%-11ld\t%-9ld\t%-6ld\t%ld\n",
MemLeak_t[i].TaskNum, MemLeak_t[i].WantSize,
MemLeak_t[i].FreeSize, MemLeak_t[i].WantTotalSize,
MemLeak_t[i].FreeTotalSize, MemLeak_t[i].MallocCount,
MemLeak_t[i].FreeCount);
}
}
ret = 0;
} else {
if ((tid >= 0 && tid < CONFIG_DMALLOC_SIZE) && MemLeak_t[tid].TaskNum) {
printf("%-8s\t%-4ld\t%-10ld\t%-8ld\t%-11ld\t%-9ld\t%-6ld\t%ld\n",
pcTaskGetName(MemLeak_t[tid].xOwner),
MemLeak_t[tid].TaskNum, MemLeak_t[tid].WantSize,
MemLeak_t[tid].FreeSize, MemLeak_t[tid].WantTotalSize,
MemLeak_t[tid].FreeTotalSize, MemLeak_t[tid].MallocCount,
MemLeak_t[tid].FreeCount);
ret = 0;
}
}
#else
if (tid == 0) {
for (i = 0; i < CONFIG_DMALLOC_SIZE; i++) {
if (MemLeak_t[i].TaskNum) {
printf("%-8s\t%-4d\t%-10d\t%-8d\t%-11d\t%-9d\t%-6d\t%d\n",
pcTaskGetName(MemLeak_t[i].xOwner),
MemLeak_t[i].TaskNum, MemLeak_t[i].WantSize,
MemLeak_t[i].FreeSize, MemLeak_t[i].WantTotalSize,
MemLeak_t[i].FreeTotalSize,
MemLeak_t[i].MallocCount, MemLeak_t[i].FreeCount);
}
if (i == 0) {
printf(
"None\t\t%-4d\t%-10d\t%-8d\t%-11d\t%-9d\t%-6d\t%d\n",
MemLeak_t[i].TaskNum, MemLeak_t[i].WantSize,
MemLeak_t[i].FreeSize, MemLeak_t[i].WantTotalSize,
MemLeak_t[i].FreeTotalSize, MemLeak_t[i].MallocCount,
MemLeak_t[i].FreeCount);
}
}
ret = 0;
} else {
if ((tid >= 0 && tid < CONFIG_DMALLOC_SIZE) && MemLeak_t[tid].TaskNum) {
printf("%-8s\t%-4d\t%-10d\t%-8d\t%-11d\t%-9d\t%-6d\t%d\n",
pcTaskGetName(MemLeak_t[tid].xOwner),
MemLeak_t[tid].TaskNum, MemLeak_t[tid].WantSize,
MemLeak_t[tid].FreeSize, MemLeak_t[tid].WantTotalSize,
MemLeak_t[tid].FreeTotalSize, MemLeak_t[tid].MallocCount,
MemLeak_t[tid].FreeCount);
ret = 0;
}
}
#endif
return ret;
}
taskENTER_CRITICAL();
for (int i = 0; i < CONFIG_DMALLOC_SIZE; i++)
{
if (i != 0 && !MemLeak_t[i].isUsed)
continue;
void xClearSpecDmallocNode(size_t tid)
{
memset(&MemLeak_t[tid], 0, sizeof(struct MemLeak));
}
// If a specific slot ID is provided, filter out other slots
if (tid != 0 && i != tid)
continue;
const char *name = (i == 0) ? "[Global/Sys]" : pcTaskGetName(MemLeak_t[i].xOwner);
printf("%-12s\t%-4lu\t%-10lu\t%-8lu\t%-11lu\t%-9lu\t%-6lu\t%lu\n",
name,
(unsigned long)MemLeak_t[i].TaskNum,
(unsigned long)MemLeak_t[i].WantSize,
(unsigned long)MemLeak_t[i].FreeSize,
(unsigned long)MemLeak_t[i].WantTotalSize,
(unsigned long)MemLeak_t[i].FreeTotalSize,
(unsigned long)MemLeak_t[i].MallocCount,
(unsigned long)MemLeak_t[i].FreeCount);
}
taskEXIT_CRITICAL();
return 0;
}
@@ -12,6 +12,6 @@
void vdRecordMalloc(size_t xWantedSize);
void vdRecordFree(size_t xFreeSize);
int vPrintDmallocInfo(int tid);
void xClearSpecDmallocNode(size_t tid);
void xClearSpecDmallocNode(void *xTask);
#endif
@@ -12,6 +12,10 @@ int vPrintFreeListAfterMallocFail(void)
BlockLink_t *pxIterator;
int total_free_size = 0;
/*
* The pxIterator.pxNextFreeBlock is never NULL.
*/
/* coverity[dereference] */
for (pxIterator = &xStart; pxIterator != pxEnd; pxIterator = pxIterator->pxNextFreeBlock)
{
printf("the address: %p, len: %d\n", pxIterator, (int)(pxIterator->xBlockSize));
@@ -55,3 +59,31 @@ void *pvPortRealloc(void *ptr, size_t size)
return p;
}
#if CONFIG_LIBC_STD_MEMALIGN
uint32_t is_memalign_ptr(void *ptr)
{
#define heapBLOCK_IS_ALLOCATED( pxBlock ) ( ( ( pxBlock->xBlockSize ) & xBlockAllocatedBit ) != 0 )
uint8_t *puc = NULL;
uint8_t *puc_pre = NULL;
BlockLink_t *pxLink;
BlockLink_t *pre_pxLink;
/* the condition guarantee the ptr is not less than zero by puc and puc_pre */
if ((uintptr_t)ptr >= (sizeof(void *) + (xHeapStructSize << 1))) {
puc = (uint8_t *)ptr;
puc -= xHeapStructSize;
puc_pre = ((void **)ptr)[-1];
puc_pre -= xHeapStructSize;
pxLink = (void *)puc;
pre_pxLink = (void *)puc_pre;
if (( heapBLOCK_IS_ALLOCATED(pxLink) == 0 ) && ( heapBLOCK_IS_ALLOCATED( pre_pxLink ) != 0 ))
return 1;
else
return 0;
}
return 0;
}
#endif
@@ -242,6 +242,10 @@ void *pvPortMalloc(size_t xWantedSize)
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
/*
* The xStart.pxNextFreeBlock is never NULL.
*/
/* coverity[dereference] */
while ((pxBlock->xBlockSize < xWantedSize) && (pxBlock->pxNextFreeBlock != NULL))
{
pxPreviousBlock = pxBlock;
@@ -298,6 +302,11 @@ void *pvPortMalloc(size_t xWantedSize)
mtCOVERAGE_TEST_MARKER();
}
#ifdef CONFIG_DMALLOC
/* memory request record by dmalloc */
vdRecordMalloc(pxBlock->xBlockSize);
#endif
/* The block is being returned - it is allocated and owned
by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit;
@@ -307,12 +316,6 @@ void *pvPortMalloc(size_t xWantedSize)
/* memory request record by med */
vPortAddToList((size_t)(((uint8_t *)pvReturn) - xHeapStructSize), dMallocsz);
#endif
#ifdef CONFIG_DMALLOC
/* memory request record by dmalloc */
vdRecordMalloc(xWantedSize);
#endif
}
else
{
@@ -410,6 +413,14 @@ void *early_reserve_pages(size_t xWantedSize)
continue;
for (j = MAX_REGION_CNT - 1; j > (i + 1); j--)
{
/*
* The loop may be unreachable when MAX_REGION_CNT is currently
* configured as 2. However, the region list is designed to support
* larger sizes (e.g. MAX_REGION_CNT >= 3), where an existing region
* may need to be shifted to make room for a newly split region.
* Do not remove this loop based on the current configuration.
*/
/* coverity[dead_error_line] */
xDefRegion[j] = xDefRegion[j - 1];
}
xDefRegion[i].xSizeInBytes = xAlignedAddress - xAddress;
@@ -492,6 +503,11 @@ void *pvPortMallocRsvAlign(size_t xWantedSize, size_t xAlignMsk)
one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
/*
* The xStart.pxNextFreeBlock is never NULL.
*/
/* coverity[dereference] */
while (((pvReturn = _pxGetAlignedAddr(pxBlock, xWantedSize, xAlignMsk, 0)) == NULL) && (pxBlock->pxNextFreeBlock != NULL))
{
pxPreviousBlock = pxBlock;
@@ -671,6 +687,10 @@ void *pvPortMallocAlign(size_t xWantedSize, size_t xAlignMsk)
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
/*
* The xStart.pxNextFreeBlock is never NULL.
*/
/* coverity[dereference] */
while (((pvReturn = _pxGetAlignedAddr(pxBlock, xWantedSize, xAlignMsk, 1)) == NULL) && (pxBlock->pxNextFreeBlock != NULL))
{
pxPreviousBlock = pxBlock;
@@ -743,6 +763,11 @@ void *pvPortMallocAlign(size_t xWantedSize, size_t xAlignMsk)
mtCOVERAGE_TEST_MARKER();
}
#ifdef CONFIG_DMALLOC
/* memory request record by dmalloc */
vdRecordMalloc(pxBlock->xBlockSize);
#endif
/* The block is being returned - it is allocated and owned
by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit;
@@ -752,11 +777,6 @@ void *pvPortMallocAlign(size_t xWantedSize, size_t xAlignMsk)
/* memory request record */
vPortAddToList((size_t)(((uint8_t *)pvReturn) - xHeapStructSize), dMallocsz);
#endif
#ifdef CONFIG_DMALLOC
/* memory request record by dmalloc */
vdRecordMalloc(xWantedSize);
#endif
}
else
{
@@ -820,11 +840,6 @@ void vPortFree(void *pv)
configASSERT((pxLink->xBlockSize & xBlockAllocatedBit) != 0);
configASSERT(pxLink->pxNextFreeBlock == NULL);
#ifdef CONFIG_DMALLOC
/* memory request record by dmalloc */
vdRecordFree(pxLink->xBlockSize);
#endif
if ((pxLink->xBlockSize & xBlockAllocatedBit) != 0)
{
if (pxLink->pxNextFreeBlock == NULL)
@@ -842,6 +857,10 @@ void vPortFree(void *pv)
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE(pv, pxLink->xBlockSize);
#ifdef CONFIG_DMALLOC
/* memory request record by dmalloc */
vdRecordFree(pxLink->xBlockSize);
#endif
#ifdef CONFIG_MEMORY_ERROR_DETECTION
vPortRmFromList((size_t)pxLink);
#endif
@@ -900,6 +919,10 @@ static void prvInsertBlockIntoFreeList(BlockLink_t *pxBlockToInsert, int isFromF
/* Iterate through the list until a block is found that has a higher address
than the block being inserted. */
/*
* The xStart.pxNextFreeBlock is never NULL.
*/
/* coverity[null_field] */
for (pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock)
{
/* Nothing to do here, just iterate to the right position. */
@@ -941,10 +964,15 @@ static void prvInsertBlockIntoFreeList(BlockLink_t *pxBlockToInsert, int isFromF
if (pxIterator->pxNextFreeBlock != pxEnd)
{
/* Form one big block from the two blocks. */
/*
* The pxIterator.pxNextFreeBlock is never NULL.
*/
/* coverity[dereference] */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
#ifdef CONFIG_MEMORY_ERROR_DETECTION
beforeNext = pxIterator->pxNextFreeBlock;
#endif
/* coverity[null_field] */
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
#ifdef CONFIG_MEMORY_ERROR_DETECTION
vFillFreedBlockHeaderWithCanary(beforeNext);
@@ -1165,7 +1193,7 @@ void vPortAddHeapRegion(uint8_t *pucStartAddress, size_t xSizeInBytes)
}
}
if (bneedsus)
xTaskResumeAll();
(void)xTaskResumeAll();
}
/* Add include implement source code which depend on the inner elements */
@@ -1262,7 +1262,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
traceTASK_DELETE( pxTCB );
#ifdef CONFIG_DMALLOC
xClearSpecDmallocNode(pxTCB->uxTCBNumber);
xClearSpecDmallocNode(pxTCB);
#endif
}
taskEXIT_CRITICAL();
@@ -3010,7 +3010,9 @@ void vTaskSwitchContext( void )
#else
ulTotalRunTime = (uint32_t)portGET_RUN_TIME_COUNTER_VALUE();
#endif
#if CONFIG_FTRACE
vTraceSwitchContext((uint32_t)pxCurrentTCB->uxTCBNumber);
#endif
/* Add the amount of time the task has been running to the
accumulated time so far. The time the task started running was
stored in ulTaskSwitchedInTime. Note that there is no overflow
@@ -3021,9 +3023,6 @@ void vTaskSwitchContext( void )
if( ulTotalRunTime > ulTaskSwitchedInTime )
{
pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
#if CONFIG_FTRACE
vTraceSwitchContext((uint32_t)pxCurrentTCB->uxTCBNumber);
#endif
}
else
{