chore: migrate project into clean repository

This commit is contained in:
yuuux
2026-08-13 16:50:52 +08:00
commit d1d25a09e7
27405 changed files with 9422808 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
[InternetShortcut]
URL=https://www.FreeRTOS.org/a00111.html
IDList=

View File

@@ -0,0 +1,165 @@
/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* The simplest possible implementation of pvPortMalloc(). Note that this
* implementation does NOT allow allocated memory to be freed again.
*
* See heap_2.c, heap_3.c and heap_4.c for alternative implementations, and the
* memory management pages of https://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
/* Allocate the memory for the heap. */
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
/* Index into the ucHeap array. */
static size_t xNextFreeByte = ( size_t ) 0U;
/*-----------------------------------------------------------*/
void * pvPortMalloc( size_t xWantedSize )
{
void * pvReturn = NULL;
static uint8_t * pucAlignedHeap = NULL;
/* Ensure that blocks are always aligned. */
#if ( portBYTE_ALIGNMENT != 1 )
{
if( xWantedSize & portBYTE_ALIGNMENT_MASK )
{
/* Byte alignment required. Check for overflow. */
if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) ) > xWantedSize )
{
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
}
else
{
xWantedSize = 0;
}
}
}
#endif /* if ( portBYTE_ALIGNMENT != 1 ) */
vTaskSuspendAll();
{
if( pucAlignedHeap == NULL )
{
/* Ensure the heap starts on a correctly aligned boundary. */
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
}
/* Check there is enough room left for the allocation and. */
if( ( xWantedSize > 0 ) && /* valid size */
( ( xNextFreeByte + xWantedSize ) < configADJUSTED_HEAP_SIZE ) &&
( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) ) /* Check for overflow. */
{
/* Return the next free byte then increment the index past this
* block. */
pvReturn = pucAlignedHeap + xNextFreeByte;
xNextFreeByte += xWantedSize;
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
vApplicationMallocFailedHook();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void * pv )
{
/* Memory cannot be freed using this scheme. See heap_2.c, heap_3.c and
* heap_4.c for alternative implementations, and the memory management pages of
* https://www.FreeRTOS.org for more information. */
( void ) pv;
/* Force an assert as it is invalid to call this function. */
configASSERT( pv == NULL );
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* Only required when static memory is not cleared. */
xNextFreeByte = ( size_t ) 0;
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return( configADJUSTED_HEAP_SIZE - xNextFreeByte );
}
/*-----------------------------------------------------------*/
/*
* Reset the state in this file. This state is normally initialized at start up.
* This function must be called by the application before restarting the
* scheduler.
*/
void vPortHeapResetState( void )
{
xNextFreeByte = ( size_t ) 0U;
}
/*-----------------------------------------------------------*/

View File

@@ -0,0 +1,401 @@
/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* A sample implementation of pvPortMalloc() and vPortFree() that permits
* allocated blocks to be freed, but does not combine adjacent free blocks
* into a single larger block (and so will fragment memory). See heap_4.c for
* an equivalent that does combine adjacent blocks into single larger blocks.
*
* See heap_1.c, heap_3.c and heap_4.c for alternative implementations, and the
* memory management pages of https://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
#include <string.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
#ifndef configHEAP_CLEAR_MEMORY_ON_FREE
#define configHEAP_CLEAR_MEMORY_ON_FREE 0
#endif
/* A few bytes might be lost to byte aligning the heap start address. */
#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/* Max value that fits in a size_t type. */
#define heapSIZE_MAX ( ~( ( size_t ) 0 ) )
/* Check if multiplying a and b will result in overflow. */
#define heapMULTIPLY_WILL_OVERFLOW( a, b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )
/* Check if adding a and b will result in overflow. */
#define heapADD_WILL_OVERFLOW( a, b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )
/* MSB of the xBlockSize member of an BlockLink_t structure is used to track
* the allocation status of a block. When MSB of the xBlockSize member of
* an BlockLink_t structure is set then the block belongs to the application.
* When the bit is free the block is still part of the free heap space. */
#define heapBLOCK_ALLOCATED_BITMASK ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) )
#define heapBLOCK_SIZE_IS_VALID( xBlockSize ) ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 )
#define heapBLOCK_IS_ALLOCATED( pxBlock ) ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 )
#define heapALLOCATE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK )
#define heapFREE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK )
/*-----------------------------------------------------------*/
/* Allocate the memory for the heap. */
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
/* Define the linked list structure. This is used to link free blocks in order
* of their size. */
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. */
} BlockLink_t;
static const size_t xHeapStructSize = ( ( sizeof( BlockLink_t ) + ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ) );
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize * 2 ) )
/* Create a couple of list links to mark the start and end of the list. */
PRIVILEGED_DATA static BlockLink_t xStart, xEnd;
/* Keeps track of the number of free bytes remaining, but says nothing about
* fragmentation. */
PRIVILEGED_DATA static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;
/* Indicates whether the heap has been initialised or not. */
PRIVILEGED_DATA static BaseType_t xHeapHasBeenInitialised = pdFALSE;
/*-----------------------------------------------------------*/
/*
* Initialises the heap structures before their first use.
*/
static void prvHeapInit( void ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/
/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
/*
* Insert a block into the list of free blocks - which is ordered by size of
* the block. Small blocks at the start of the list and large blocks at the end
* of the list.
*/
#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \
{ \
BlockLink_t * pxIterator; \
size_t xBlockSize; \
\
xBlockSize = pxBlockToInsert->xBlockSize; \
\
/* Iterate through the list until a block is found that has a larger size */ \
/* than the block we are inserting. */ \
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \
{ \
/* There is nothing to do here - just iterate to the correct position. */ \
} \
\
/* Update the list to include the block being inserted in the correct */ \
/* position. */ \
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \
pxIterator->pxNextFreeBlock = pxBlockToInsert; \
}
/*-----------------------------------------------------------*/
void * pvPortMalloc( size_t xWantedSize )
{
BlockLink_t * pxBlock;
BlockLink_t * pxPreviousBlock;
BlockLink_t * pxNewBlockLink;
void * pvReturn = NULL;
size_t xAdditionalRequiredSize;
if( xWantedSize > 0 )
{
/* The wanted size must be increased so it can contain a BlockLink_t
* structure in addition to the requested amount of bytes. */
if( heapADD_WILL_OVERFLOW( xWantedSize, xHeapStructSize ) == 0 )
{
xWantedSize += xHeapStructSize;
/* Ensure that blocks are always aligned to the required number
* of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xAdditionalRequiredSize = portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK );
if( heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0 )
{
xWantedSize += xAdditionalRequiredSize;
}
else
{
xWantedSize = 0;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
xWantedSize = 0;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
* initialisation to setup the list of free blocks. */
if( xHeapHasBeenInitialised == pdFALSE )
{
prvHeapInit();
xHeapHasBeenInitialised = pdTRUE;
}
/* Check the block size we are trying to allocate 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( heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0 )
{
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Blocks are stored in byte order - traverse the list from the start
* (smallest) block until one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* If we found the end marker then a block of adequate size was not found. */
if( pxBlock != &xEnd )
{
/* Return the memory space - jumping over the BlockLink_t structure
* at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
/* 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;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks.
* The list of free blocks is sorted by their size, we have to
* iterate to find the right place to insert new block. */
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
/* The block is being returned - it is allocated and owned
* by the application and has no "next" block. */
heapALLOCATE_BLOCK( pxBlock );
pxBlock->pxNextFreeBlock = NULL;
}
}
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
vApplicationMallocFailedHook();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
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 -= xHeapStructSize;
/* This unexpected casting is to keep some compilers from issuing
* byte alignment warnings. */
pxLink = ( void * ) puc;
configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )
{
/* The block is being returned to the heap - it is no longer
* allocated. */
heapFREE_BLOCK( pxLink );
#if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
{
( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );
}
#endif
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
}
( void ) xTaskResumeAll();
}
}
}
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/
void * pvPortCalloc( size_t xNum,
size_t xSize )
{
void * pv = NULL;
if( heapMULTIPLY_WILL_OVERFLOW( xNum, xSize ) == 0 )
{
pv = pvPortMalloc( xNum * xSize );
if( pv != NULL )
{
( void ) memset( pv, 0, xNum * xSize );
}
}
return pv;
}
/*-----------------------------------------------------------*/
static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
{
BlockLink_t * pxFirstFreeBlock;
uint8_t * pucAlignedHeap;
/* Ensure the heap starts on a correctly aligned boundary. */
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) & ucHeap[ portBYTE_ALIGNMENT - 1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
/* 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 = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/* xEnd is used to mark the end of the list of free blocks. */
xEnd.xBlockSize = configADJUSTED_HEAP_SIZE;
xEnd.pxNextFreeBlock = NULL;
/* To start with there is a single free block that is sized to take up the
* entire heap space. */
pxFirstFreeBlock = ( BlockLink_t * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE;
pxFirstFreeBlock->pxNextFreeBlock = &xEnd;
}
/*-----------------------------------------------------------*/
/*
* Reset the state in this file. This state is normally initialized at start up.
* This function must be called by the application before restarting the
* scheduler.
*/
void vPortHeapResetState( void )
{
xFreeBytesRemaining = configADJUSTED_HEAP_SIZE;
xHeapHasBeenInitialised = pdFALSE;
}
/*-----------------------------------------------------------*/

View File

@@ -0,0 +1,106 @@
/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* Implementation of pvPortMalloc() and vPortFree() that relies on the
* compilers own malloc() and free() implementations.
*
* This file can only be used if the linker is configured to to generate
* a heap memory area.
*
* See heap_1.c, heap_2.c and heap_4.c for alternative implementations, and the
* memory management pages of https://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
/*-----------------------------------------------------------*/
void * pvPortMalloc( size_t xWantedSize )
{
void * pvReturn;
vTaskSuspendAll();
{
pvReturn = malloc( xWantedSize );
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
vApplicationMallocFailedHook();
}
}
#endif
return pvReturn;
}
/*-----------------------------------------------------------*/
void vPortFree( void * pv )
{
if( pv != NULL )
{
vTaskSuspendAll();
{
free( pv );
traceFREE( pv, 0 );
}
( void ) xTaskResumeAll();
}
}
/*-----------------------------------------------------------*/
/*
* Reset the state in this file. This state is normally initialized at start up.
* This function must be called by the application before restarting the
* scheduler.
*/
void vPortHeapResetState( void )
{
/* No state needs to be re-initialised in heap_3. */
}
/*-----------------------------------------------------------*/

View File

@@ -0,0 +1,742 @@
/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* A sample implementation of pvPortMalloc() and vPortFree() that combines
* (coalescences) adjacent memory blocks as they are freed, and in so doing
* limits memory fragmentation.
*
* See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
* memory management pages of https://www.FreeRTOS.org for more information.
*/
#include <stdlib.h>
#include <string.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
#ifndef configHEAP_CLEAR_MEMORY_ON_FREE
#define configHEAP_CLEAR_MEMORY_ON_FREE 0
#endif
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/* Max value that fits in a size_t type. */
#define heapSIZE_MAX ( ~( ( size_t ) 0 ) )
/* Check if multiplying a and b will result in overflow. */
#define heapMULTIPLY_WILL_OVERFLOW( a, b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )
/* Check if adding a and b will result in overflow. */
#define heapADD_WILL_OVERFLOW( a, b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )
/* Check if the subtraction operation ( a - b ) will result in underflow. */
#define heapSUBTRACT_WILL_UNDERFLOW( a, b ) ( ( a ) < ( b ) )
/* MSB of the xBlockSize member of an BlockLink_t structure is used to track
* the allocation status of a block. When MSB of the xBlockSize member of
* an BlockLink_t structure is set then the block belongs to the application.
* When the bit is free the block is still part of the free heap space. */
#define heapBLOCK_ALLOCATED_BITMASK ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) )
#define heapBLOCK_SIZE_IS_VALID( xBlockSize ) ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 )
#define heapBLOCK_IS_ALLOCATED( pxBlock ) ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 )
#define heapALLOCATE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK )
#define heapFREE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK )
/*-----------------------------------------------------------*/
/* Allocate the memory for the heap. */
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */
extern uint8_t __vmaof_osheap;
PRIVILEGED_DATA static uint8_t *ucHeap = &__vmaof_osheap;
#else
PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
/* 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. */
} BlockLink_t;
/* Setting configENABLE_HEAP_PROTECTOR to 1 enables heap block pointers
* protection using an application supplied canary value to catch heap
* corruption should a heap buffer overflow occur.
*/
#if ( configENABLE_HEAP_PROTECTOR == 1 )
/**
* @brief Application provided function to get a random value to be used as canary.
*
* @param pxHeapCanary [out] Output parameter to return the canary value.
*/
extern void vApplicationGetRandomHeapCanary( portPOINTER_SIZE_TYPE * pxHeapCanary );
/* Canary value for protecting internal heap pointers. */
PRIVILEGED_DATA static portPOINTER_SIZE_TYPE xHeapCanary;
/* Macro to load/store BlockLink_t pointers to memory. By XORing the
* pointers with a random canary value, heap overflows will result
* in randomly unpredictable pointer values which will be caught by
* heapVALIDATE_BLOCK_POINTER assert. */
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( ( BlockLink_t * ) ( ( ( portPOINTER_SIZE_TYPE ) ( pxBlock ) ) ^ xHeapCanary ) )
#else
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( pxBlock )
#endif /* configENABLE_HEAP_PROTECTOR */
/* Assert that a heap block pointer is within the heap bounds. */
#define heapVALIDATE_BLOCK_POINTER( pxBlock ) \
configASSERT( ( ( uint8_t * ) ( pxBlock ) >= &( ucHeap[ 0 ] ) ) && \
( ( uint8_t * ) ( pxBlock ) <= &( ucHeap[ configTOTAL_HEAP_SIZE - 1 ] ) ) )
/*-----------------------------------------------------------*/
/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks. The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) PRIVILEGED_FUNCTION;
/*
* Called automatically to setup the required heap structures the first time
* pvPortMalloc() is called.
*/
static void prvHeapInit( void ) PRIVILEGED_FUNCTION;
/*-----------------------------------------------------------*/
/* 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 );
/* Create a couple of list links to mark the start and end of the list. */
PRIVILEGED_DATA static BlockLink_t xStart;
PRIVILEGED_DATA static BlockLink_t * pxEnd = NULL;
/* Keeps track of the number of calls to allocate and free memory as well as the
* number of free bytes remaining, but says nothing about fragmentation. */
PRIVILEGED_DATA static size_t xTotalHeapSize = ( configTOTAL_HEAP_SIZE );
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;
/*-----------------------------------------------------------*/
void * pvPortMalloc( size_t xWantedSize )
{
BlockLink_t * pxBlock;
BlockLink_t * pxPreviousBlock;
BlockLink_t * pxNewBlockLink;
void * pvReturn = NULL;
size_t xAdditionalRequiredSize;
if( xWantedSize > 0 )
{
/* The wanted size must be increased so it can contain a BlockLink_t
* structure in addition to the requested amount of bytes. */
if( heapADD_WILL_OVERFLOW( xWantedSize, xHeapStructSize ) == 0 )
{
xWantedSize += xHeapStructSize;
/* Ensure that blocks are always aligned to the required number
* of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xAdditionalRequiredSize = portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK );
if( heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0 )
{
xWantedSize += xAdditionalRequiredSize;
}
else
{
xWantedSize = 0;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
xWantedSize = 0;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
* initialisation to setup the list of free blocks. */
if( pxEnd == NULL )
{
prvHeapInit();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Check the block size we are trying to allocate 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( heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0 )
{
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Traverse the list from the start (lowest address) block until
* one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
heapVALIDATE_BLOCK_POINTER( pxBlock );
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
{
pxPreviousBlock = pxBlock;
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
heapVALIDATE_BLOCK_POINTER( pxBlock );
}
/* If the end marker was reached then a block of adequate size
* was not found. */
if( pxBlock != pxEnd )
{
/* Return the memory space pointed to - jumping over the
* BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxPreviousBlock->pxNextFreeBlock ) ) + xHeapStructSize );
heapVALIDATE_BLOCK_POINTER( pvReturn );
/* 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. */
configASSERT( heapSUBTRACT_WILL_UNDERFLOW( pxBlock->xBlockSize, xWantedSize ) == 0 );
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 );
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
/* Calculate the sizes of two blocks split from the
* single block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
pxNewBlockLink->pxNextFreeBlock = pxPreviousBlock->pxNextFreeBlock;
pxPreviousBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( 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. */
heapALLOCATE_BLOCK( pxBlock );
pxBlock->pxNextFreeBlock = NULL;
xNumberOfSuccessfulAllocations++;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}
/*-----------------------------------------------------------*/
void *pvPortRealloc( void *srcAddr, size_t xWantedSize )
{
uint8_t *srcaddr = (uint8_t *)srcAddr;
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
BlockLink_t *pxBlockold, *pxBlockjudge;
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
initialisation to setup the list of free blocks. */
if( pxEnd == NULL )
{
prvHeapInit();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* 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( heapBLOCK_SIZE_IS_VALID(xWantedSize) == 0 )
{
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
if(srcaddr == NULL)
{
pvReturn = pvPortMalloc(xWantedSize);
( void ) xTaskResumeAll();
return pvReturn;
}
/* find the start block address of the source address */
pxBlockold = (BlockLink_t *)(srcaddr - xHeapStructSize);
/* find the end block address of the source address */
pxBlockjudge = (BlockLink_t *)((uint8_t*)pxBlockold + heapFREE_BLOCK(pxBlockold));
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
/* check the next block is validate */
while(pxBlock != pxBlockjudge && ( pxBlock->pxNextFreeBlock != NULL ))
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* the next block is validate, and the block size large than wanted */
if( xWantedSize < pxBlock->xBlockSize
&& pxBlock->xBlockSize - xWantedSize > heapMINIMUM_BLOCK_SIZE && pxBlock == pxBlockjudge)
{
pxBlockold->xBlockSize += xWantedSize;
pxNewBlockLink = (BlockLink_t *)((uint8_t*)pxBlock + xWantedSize);
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( pxNewBlockLink );
pxBlock->pxNextFreeBlock = NULL;
pvReturn = srcaddr;
xFreeBytesRemaining -= xWantedSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
}
else
{
// the next block is invalidate, so alloc a new block,
// and witch size equal to the wanted size plus current block size
pvReturn = pvPortMalloc(heapFREE_BLOCK(pxBlockold) - xHeapStructSize + xWantedSize);
memcpy(pvReturn, srcaddr, heapFREE_BLOCK(pxBlockold) - xHeapStructSize);
// free the source space
vPortFree(srcaddr);
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
( void ) xTaskResumeAll();
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}
/*-----------------------------------------------------------*/
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 -= xHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
heapVALIDATE_BLOCK_POINTER( pxLink );
configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )
{
/* The block is being returned to the heap - it is no longer
* allocated. */
heapFREE_BLOCK( pxLink );
#if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
{
/* Check for underflow as this can occur if xBlockSize is
* overwritten in a heap block. */
if( heapSUBTRACT_WILL_UNDERFLOW( pxLink->xBlockSize, xHeapStructSize ) == 0 )
{
( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );
}
}
#endif
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
xNumberOfSuccessfulFrees++;
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
size_t xPortGetTotalHeapSize( void )
{
return xTotalHeapSize;
}
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/
void * pvPortCalloc( size_t xNum,
size_t xSize )
{
void * pv = NULL;
if( heapMULTIPLY_WILL_OVERFLOW( xNum, xSize ) == 0 )
{
pv = pvPortMalloc( xNum * xSize );
if( pv != NULL )
{
( void ) memset( pv, 0, xNum * xSize );
}
}
return pv;
}
/*-----------------------------------------------------------*/
static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
{
BlockLink_t * pxFirstFreeBlock;
portPOINTER_SIZE_TYPE uxStartAddress, uxEndAddress;
/* Ensure the heap starts on a correctly aligned boundary. */
uxStartAddress = ( portPOINTER_SIZE_TYPE ) ucHeap;
if( ( uxStartAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxStartAddress += ( portBYTE_ALIGNMENT - 1 );
uxStartAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= ( size_t ) ( uxStartAddress - ( portPOINTER_SIZE_TYPE ) ucHeap );
}
#if ( configENABLE_HEAP_PROTECTOR == 1 )
{
vApplicationGetRandomHeapCanary( &( xHeapCanary ) );
}
#endif
/* 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 = ( void * ) heapPROTECT_BLOCK_POINTER( uxStartAddress );
xStart.xBlockSize = ( size_t ) 0;
/* pxEnd is used to mark the end of the list of free blocks and is inserted
* at the end of the heap space. */
uxEndAddress = uxStartAddress + ( portPOINTER_SIZE_TYPE ) xTotalHeapSize;
uxEndAddress -= ( portPOINTER_SIZE_TYPE ) xHeapStructSize;
uxEndAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( BlockLink_t * ) uxEndAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( NULL );
/* To start with there is a single free block that is sized to take up the
* entire heap space, minus the space taken by pxEnd. */
pxFirstFreeBlock = ( BlockLink_t * ) uxStartAddress;
pxFirstFreeBlock->xBlockSize = ( size_t ) ( uxEndAddress - ( portPOINTER_SIZE_TYPE ) pxFirstFreeBlock );
pxFirstFreeBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );
/* Only one block exists - and it covers the entire usable heap space. */
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
}
/*-----------------------------------------------------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
{
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; heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) < pxBlockToInsert; pxIterator = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
{
/* Nothing to do here, just iterate to the right position. */
}
if( pxIterator != &xStart )
{
heapVALIDATE_BLOCK_POINTER( pxIterator );
}
/* Do the block being inserted, and the block it is being inserted after
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
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? */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
{
if( heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
/* If the block being inserted plugged a gab, 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 = heapPROTECT_BLOCK_POINTER( pxBlockToInsert );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/
void vPortGetHeapStats( HeapStats_t * pxHeapStats )
{
BlockLink_t * pxBlock;
size_t xBlocks = 0, xMaxSize = 0, xMinSize = (size_t)portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
vTaskSuspendAll();
{
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
/* pxBlock will be NULL if the heap has not been initialised. The heap
* is initialised automatically when the first allocation is made. */
if( pxBlock != NULL )
{
while( pxBlock != pxEnd )
{
/* Increment the number of blocks and record the largest block seen
* so far. */
xBlocks++;
if( pxBlock->xBlockSize > xMaxSize )
{
xMaxSize = pxBlock->xBlockSize;
}
if( pxBlock->xBlockSize < xMinSize )
{
xMinSize = pxBlock->xBlockSize;
}
/* Move to the next block in the chain until the last block is
* reached. */
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
}
}
}
( void ) xTaskResumeAll();
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
taskENTER_CRITICAL();
{
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
}
taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
/*
* Reset the state in this file. This state is normally initialized at start up.
* This function must be called by the application before restarting the
* scheduler.
*/
void vPortHeapResetState( void )
{
pxEnd = NULL;
xFreeBytesRemaining = ( size_t ) 0U;
xMinimumEverFreeBytesRemaining = ( size_t ) 0U;
xNumberOfSuccessfulAllocations = ( size_t ) 0U;
xNumberOfSuccessfulFrees = ( size_t ) 0U;
}
/*-----------------------------------------------------------*/

View File

@@ -0,0 +1,730 @@
/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* A sample implementation of pvPortMalloc() that allows the heap to be defined
* across multiple non-contiguous blocks and combines (coalescences) adjacent
* memory blocks as they are freed.
*
* See heap_1.c, heap_2.c, heap_3.c and heap_4.c for alternative
* implementations, and the memory management pages of https://www.FreeRTOS.org
* for more information.
*
* Usage notes:
*
* vPortDefineHeapRegions() ***must*** be called before pvPortMalloc().
* pvPortMalloc() will be called if any task objects (tasks, queues, event
* groups, etc.) are created, therefore vPortDefineHeapRegions() ***must*** be
* called before any other objects are defined.
*
* vPortDefineHeapRegions() takes a single parameter. The parameter is an array
* of HeapRegion_t structures. HeapRegion_t is defined in portable.h as
*
* 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.
* } HeapRegion_t;
*
* The array is terminated using a NULL zero sized region definition, and the
* memory regions defined in the array ***must*** appear in address order from
* low address to high address. So the following is a valid example of how
* to use the function.
*
* HeapRegion_t xHeapRegions[] =
* {
* { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000
* { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000
* { NULL, 0 } << Terminates the array.
* };
*
* vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions().
*
* Note 0x80000000 is the lower address so appears in the array first.
*
*/
#include <stdlib.h>
#include <string.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
#ifndef configHEAP_CLEAR_MEMORY_ON_FREE
#define configHEAP_CLEAR_MEMORY_ON_FREE 0
#endif
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
/* Max value that fits in a size_t type. */
#define heapSIZE_MAX ( ~( ( size_t ) 0 ) )
/* Check if multiplying a and b will result in overflow. */
#define heapMULTIPLY_WILL_OVERFLOW( a, b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )
/* Check if adding a and b will result in overflow. */
#define heapADD_WILL_OVERFLOW( a, b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )
/* Check if the subtraction operation ( a - b ) will result in underflow. */
#define heapSUBTRACT_WILL_UNDERFLOW( a, b ) ( ( a ) < ( b ) )
/* MSB of the xBlockSize member of an BlockLink_t structure is used to track
* the allocation status of a block. When MSB of the xBlockSize member of
* an BlockLink_t structure is set then the block belongs to the application.
* When the bit is free the block is still part of the free heap space. */
#define heapBLOCK_ALLOCATED_BITMASK ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) )
#define heapBLOCK_SIZE_IS_VALID( xBlockSize ) ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 )
#define heapBLOCK_IS_ALLOCATED( pxBlock ) ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 )
#define heapALLOCATE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK )
#define heapFREE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK )
/* Setting configENABLE_HEAP_PROTECTOR to 1 enables heap block pointers
* protection using an application supplied canary value to catch heap
* corruption should a heap buffer overflow occur.
*/
#if ( configENABLE_HEAP_PROTECTOR == 1 )
/* Macro to load/store BlockLink_t pointers to memory. By XORing the
* pointers with a random canary value, heap overflows will result
* in randomly unpredictable pointer values which will be caught by
* heapVALIDATE_BLOCK_POINTER assert. */
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( ( BlockLink_t * ) ( ( ( portPOINTER_SIZE_TYPE ) ( pxBlock ) ) ^ xHeapCanary ) )
/* Assert that a heap block pointer is within the heap bounds. */
#define heapVALIDATE_BLOCK_POINTER( pxBlock ) \
configASSERT( ( pucHeapHighAddress != NULL ) && \
( pucHeapLowAddress != NULL ) && \
( ( uint8_t * ) ( pxBlock ) >= pucHeapLowAddress ) && \
( ( uint8_t * ) ( pxBlock ) < pucHeapHighAddress ) )
#else /* if ( configENABLE_HEAP_PROTECTOR == 1 ) */
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( pxBlock )
#define heapVALIDATE_BLOCK_POINTER( pxBlock )
#endif /* configENABLE_HEAP_PROTECTOR */
/*-----------------------------------------------------------*/
/* 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. */
} BlockLink_t;
/*-----------------------------------------------------------*/
/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks. The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) PRIVILEGED_FUNCTION;
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) PRIVILEGED_FUNCTION;
#if ( configENABLE_HEAP_PROTECTOR == 1 )
/**
* @brief Application provided function to get a random value to be used as canary.
*
* @param pxHeapCanary [out] Output parameter to return the canary value.
*/
extern void vApplicationGetRandomHeapCanary( portPOINTER_SIZE_TYPE * pxHeapCanary );
#endif /* configENABLE_HEAP_PROTECTOR */
/*-----------------------------------------------------------*/
/* 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 );
/* Create a couple of list links to mark the start and end of the list. */
PRIVILEGED_DATA static BlockLink_t xStart;
PRIVILEGED_DATA static BlockLink_t * pxEnd = NULL;
/* Keeps track of the number of calls to allocate and free memory as well as the
* number of free bytes remaining, but says nothing about fragmentation. */
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 ( configENABLE_HEAP_PROTECTOR == 1 )
/* Canary value for protecting internal heap pointers. */
PRIVILEGED_DATA static portPOINTER_SIZE_TYPE xHeapCanary;
/* Highest and lowest heap addresses used for heap block bounds checking. */
PRIVILEGED_DATA static uint8_t * pucHeapHighAddress = NULL;
PRIVILEGED_DATA static uint8_t * pucHeapLowAddress = NULL;
#endif /* configENABLE_HEAP_PROTECTOR */
/*-----------------------------------------------------------*/
void * pvPortMalloc( size_t xWantedSize )
{
BlockLink_t * pxBlock;
BlockLink_t * pxPreviousBlock;
BlockLink_t * pxNewBlockLink;
void * pvReturn = NULL;
size_t xAdditionalRequiredSize;
/* The heap must be initialised before the first call to
* pvPortMalloc(). */
configASSERT( pxEnd );
if( xWantedSize > 0 )
{
/* The wanted size must be increased so it can contain a BlockLink_t
* structure in addition to the requested amount of bytes. */
if( heapADD_WILL_OVERFLOW( xWantedSize, xHeapStructSize ) == 0 )
{
xWantedSize += xHeapStructSize;
/* Ensure that blocks are always aligned to the required number
* of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xAdditionalRequiredSize = portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK );
if( heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0 )
{
xWantedSize += xAdditionalRequiredSize;
}
else
{
xWantedSize = 0;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
xWantedSize = 0;
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
vTaskSuspendAll();
{
/* Check the block size we are trying to allocate 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( heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0 )
{
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Traverse the list from the start (lowest address) block until
* one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
heapVALIDATE_BLOCK_POINTER( pxBlock );
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
{
pxPreviousBlock = pxBlock;
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
heapVALIDATE_BLOCK_POINTER( pxBlock );
}
/* If the end marker was reached then a block of adequate size
* was not found. */
if( pxBlock != pxEnd )
{
/* Return the memory space pointed to - jumping over the
* BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxPreviousBlock->pxNextFreeBlock ) ) + xHeapStructSize );
heapVALIDATE_BLOCK_POINTER( pvReturn );
/* 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. */
configASSERT( heapSUBTRACT_WILL_UNDERFLOW( pxBlock->xBlockSize, xWantedSize ) == 0 );
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 );
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
/* Calculate the sizes of two blocks split from the
* single block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
pxNewBlockLink->pxNextFreeBlock = pxPreviousBlock->pxNextFreeBlock;
pxPreviousBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( 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. */
heapALLOCATE_BLOCK( pxBlock );
pxBlock->pxNextFreeBlock = NULL;
xNumberOfSuccessfulAllocations++;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}
/*-----------------------------------------------------------*/
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 -= xHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
heapVALIDATE_BLOCK_POINTER( pxLink );
configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )
{
/* The block is being returned to the heap - it is no longer
* allocated. */
heapFREE_BLOCK( pxLink );
#if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
{
/* Check for underflow as this can occur if xBlockSize is
* overwritten in a heap block. */
if( heapSUBTRACT_WILL_UNDERFLOW( pxLink->xBlockSize, xHeapStructSize ) == 0 )
{
( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );
}
}
#endif
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
xNumberOfSuccessfulFrees++;
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void * pvPortCalloc( size_t xNum,
size_t xSize )
{
void * pv = NULL;
if( heapMULTIPLY_WILL_OVERFLOW( xNum, xSize ) == 0 )
{
pv = pvPortMalloc( xNum * xSize );
if( pv != NULL )
{
( void ) memset( pv, 0, xNum * xSize );
}
}
return pv;
}
/*-----------------------------------------------------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
{
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; heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) < pxBlockToInsert; pxIterator = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
{
/* Nothing to do here, just iterate to the right position. */
}
if( pxIterator != &xStart )
{
heapVALIDATE_BLOCK_POINTER( pxIterator );
}
/* Do the block being inserted, and the block it is being inserted after
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
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? */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
{
if( heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( 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 = heapPROTECT_BLOCK_POINTER( pxBlockToInsert );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions ) /* PRIVILEGED_FUNCTION */
{
BlockLink_t * pxFirstFreeBlockInRegion = NULL;
BlockLink_t * pxPreviousFreeBlock;
portPOINTER_SIZE_TYPE xAlignedHeap;
size_t xTotalRegionSize, xTotalHeapSize = 0;
BaseType_t xDefinedRegions = 0;
portPOINTER_SIZE_TYPE xAddress;
const HeapRegion_t * pxHeapRegion;
/* Can only call once! */
configASSERT( pxEnd == NULL );
#if ( configENABLE_HEAP_PROTECTOR == 1 )
{
vApplicationGetRandomHeapCanary( &( xHeapCanary ) );
}
#endif
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
while( pxHeapRegion->xSizeInBytes > 0 )
{
xTotalRegionSize = pxHeapRegion->xSizeInBytes;
/* Ensure the heap region starts on a correctly aligned boundary. */
xAddress = ( portPOINTER_SIZE_TYPE ) pxHeapRegion->pucStartAddress;
if( ( xAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
xAddress += ( portBYTE_ALIGNMENT - 1 );
xAddress &= ~( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK;
/* Adjust the size for the bytes lost to alignment. */
xTotalRegionSize -= ( size_t ) ( xAddress - ( portPOINTER_SIZE_TYPE ) pxHeapRegion->pucStartAddress );
}
xAlignedHeap = xAddress;
/* 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 * ) heapPROTECT_BLOCK_POINTER( xAlignedHeap );
xStart.xBlockSize = ( size_t ) 0;
}
else
{
/* Should only get here if one region has already been added to the
* heap. */
configASSERT( pxEnd != heapPROTECT_BLOCK_POINTER( NULL ) );
/* Check blocks are passed in with increasing start addresses. */
configASSERT( ( size_t ) xAddress > ( size_t ) pxEnd );
}
#if ( configENABLE_HEAP_PROTECTOR == 1 )
{
if( ( pucHeapLowAddress == NULL ) ||
( ( uint8_t * ) xAlignedHeap < pucHeapLowAddress ) )
{
pucHeapLowAddress = ( uint8_t * ) xAlignedHeap;
}
}
#endif /* configENABLE_HEAP_PROTECTOR */
/* 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. */
xAddress = xAlignedHeap + ( portPOINTER_SIZE_TYPE ) xTotalRegionSize;
xAddress -= ( portPOINTER_SIZE_TYPE ) xHeapStructSize;
xAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( BlockLink_t * ) xAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( NULL );
/* 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 * ) xAlignedHeap;
pxFirstFreeBlockInRegion->xBlockSize = ( size_t ) ( xAddress - ( portPOINTER_SIZE_TYPE ) pxFirstFreeBlockInRegion );
pxFirstFreeBlockInRegion->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );
/* 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 = heapPROTECT_BLOCK_POINTER( pxFirstFreeBlockInRegion );
}
xTotalHeapSize += pxFirstFreeBlockInRegion->xBlockSize;
#if ( configENABLE_HEAP_PROTECTOR == 1 )
{
if( ( pucHeapHighAddress == NULL ) ||
( ( ( ( uint8_t * ) pxFirstFreeBlockInRegion ) + pxFirstFreeBlockInRegion->xBlockSize ) > pucHeapHighAddress ) )
{
pucHeapHighAddress = ( ( uint8_t * ) pxFirstFreeBlockInRegion ) + pxFirstFreeBlockInRegion->xBlockSize;
}
}
#endif
/* Move onto the next HeapRegion_t structure. */
xDefinedRegions++;
pxHeapRegion = &( pxHeapRegions[ xDefinedRegions ] );
}
xMinimumEverFreeBytesRemaining = xTotalHeapSize;
xFreeBytesRemaining = xTotalHeapSize;
/* Check something was actually defined before it is accessed. */
configASSERT( xTotalHeapSize );
}
/*-----------------------------------------------------------*/
void vPortGetHeapStats( HeapStats_t * pxHeapStats )
{
BlockLink_t * pxBlock;
size_t xBlocks = 0, xMaxSize = 0, xMinSize = (size_t)portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
vTaskSuspendAll();
{
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
/* pxBlock will be NULL if the heap has not been initialised. The heap
* is initialised automatically when the first allocation is made. */
if( pxBlock != NULL )
{
while( pxBlock != pxEnd )
{
/* Increment the number of blocks and record the largest block seen
* so far. */
xBlocks++;
if( pxBlock->xBlockSize > xMaxSize )
{
xMaxSize = pxBlock->xBlockSize;
}
/* Heap five will have a zero sized block at the end of each
* each region - the block is only used to link to the next
* heap region so it not a real block. */
if( pxBlock->xBlockSize != 0 )
{
if( pxBlock->xBlockSize < xMinSize )
{
xMinSize = pxBlock->xBlockSize;
}
}
/* Move to the next block in the chain until the last block is
* reached. */
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
}
}
}
( void ) xTaskResumeAll();
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
taskENTER_CRITICAL();
{
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
}
taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
/*
* Reset the state in this file. This state is normally initialized at start up.
* This function must be called by the application before restarting the
* scheduler.
*/
void vPortHeapResetState( void )
{
pxEnd = NULL;
xFreeBytesRemaining = ( size_t ) 0U;
xMinimumEverFreeBytesRemaining = ( size_t ) 0U;
xNumberOfSuccessfulAllocations = ( size_t ) 0U;
xNumberOfSuccessfulFrees = ( size_t ) 0U;
#if ( configENABLE_HEAP_PROTECTOR == 1 )
pucHeapHighAddress = NULL;
pucHeapLowAddress = NULL;
#endif /* #if ( configENABLE_HEAP_PROTECTOR == 1 ) */
}
/*-----------------------------------------------------------*/

View File

@@ -0,0 +1,778 @@
/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the Nuclei N/NX Processor port.
*----------------------------------------------------------*/
/* Scheduler includes. */
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "chip.h"
//#define ENABLE_KERNEL_DEBUG
#ifdef ENABLE_KERNEL_DEBUG
#define FREERTOS_PORT_DEBUG(...) printf(__VA_ARGS__)
#else
#define FREERTOS_PORT_DEBUG(...)
#endif
#ifndef configSYSTICK_CLOCK_HZ
#define configSYSTICK_CLOCK_HZ SOC_TIMER_FREQ
#endif
#ifndef configKERNEL_INTERRUPT_PRIORITY
#define configKERNEL_INTERRUPT_PRIORITY 0
#endif
#ifndef configMAX_SYSCALL_INTERRUPT_PRIORITY
// See function prvCheckMaxSysCallPrio and prvCalcMaxSysCallMTH
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 255
#endif
/* Constants required to check the validity of an interrupt priority. */
#define portFIRST_USER_INTERRUPT_NUMBER ( 18 )
#define SYSTICK_TICK_CONST (configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ)
/* Masks off all bits but the ECLIC MTH bits in the MTH register. */
#define portMTH_MASK ( 0xFFUL )
/* Constants required to set up the initial stack. */
#define portINITIAL_MSTATUS ( MSTATUS_MPP | MSTATUS_MPIE | MSTATUS_FS_INITIAL | MSTATUS_VS_INITIAL)
#define portINITIAL_EXC_RETURN ( 0xfffffffd )
/* The systick is a 64-bit counter. */
#define portMAX_BIT_NUMBER ( SysTimer_MTIMER_Msk )
/* A fiddle factor to estimate the number of SysTick counts that would have
occurred while the SysTick counter is stopped during tickless idle
calculations. */
#define portMISSED_COUNTS_FACTOR ( 45UL )
/* Let the user override the pre-loading of the initial LR with the address of
prvTaskExitError() in case it messes up unwinding of the stack in the
debugger. */
#ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else
#define portTASK_RETURN_ADDRESS prvTaskExitError
#endif
/*
* Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/
void vPortSetupTimerInterrupt(void);
/*
* Exception handlers.
*/
void xPortSysTickHandler(void);
/*
* Start first task is a separate function so it can be tested in isolation.
*/
extern void prvPortStartFirstTask(void) __attribute__((naked));
/*
* Used to catch tasks that attempt to return from their implementing function.
*/
static void prvTaskExitError(void);
#define xPortSysTickHandler eclic_mtip_handler
/*-----------------------------------------------------------*/
/* Each task maintains its own interrupt status in the critical nesting
variable. */
UBaseType_t uxCriticalNesting = 0; //0xaaaaaaaa;
/*
* Record the real MTH calculated by the configMAX_SYSCALL_INTERRUPT_PRIORITY
* The configMAX_SYSCALL_INTERRUPT_PRIORITY is not the left-aligned level value,
* See equations below:
* Level Bits number: lvlbits = min(nlbits, CLICINTCTLBITS)
* Left align Bits number: lfabits = 8-lvlbits
* 0 < configMAX_SYSCALL_INTERRUPT_PRIORITY <= (2^lvlbits-1)
* uxMaxSysCallMTH = (configMAX_SYSCALL_INTERRUPT_PRIORITY << lfabits) | ((2^lfabits)-1)
* If nlbits = 3, CLICINTCTLBITS=3, then lvlbits = 3, lfabits = 5
* Set configMAX_SYSCALL_INTERRUPT_PRIORITY to 6
* Then uxMaxSysCallMTH = (6<<5) | (2^5 - 1) = 223
*
* See function prvCheckMaxSysCallPrio and prvCalcMaxSysCallMTH
*/
uint8_t uxMaxSysCallMTH = 255;
/*
* The number of SysTick increments that make up one tick period.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static TickType_t ulTimerCountsForOneTick = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* The maximum number of tick periods that can be suppressed is limited by the
* 24 bit resolution of the SysTick timer.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static TickType_t xMaximumPossibleSuppressedTicks = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Compensate for the CPU cycles that pass while the SysTick is stopped (low
* power functionality only.
*/
#if( configUSE_TICKLESS_IDLE == 1 )
static TickType_t ulStoppedTimerCompensation = 0;
#endif /* configUSE_TICKLESS_IDLE */
/*
* Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
* FreeRTOS API functions are not called from interrupts that have been assigned
* a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
*/
#if( configASSERT_DEFINED == 1 )
static uint8_t ucMaxSysCallPriority = 0;
#endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/
/*
* See header file for description.
* As per the standard RISC-V ABI pxTopcOfStack is passed in in a0, pxCode in
* a1, and pvParameters in a2. The new top of stack is passed out in a0.
*
* RISC-V maps registers to ABI names as follows (X1 to X31 integer registers
* for the 'I' profile, X1 to X15 for the 'E' profile, currently I assumed).
*
* Register ABI Name Description Saver
* x0 zero Hard-wired zero -
* x1 ra Return address Caller
* x2 sp Stack pointer Callee
* x3 gp Global pointer -
* x4 tp Thread pointer -
* x5-7 t0-2 Temporaries Caller
* x8 s0/fp Saved register/Frame pointer Callee
* x9 s1 Saved register Callee
* x10-11 a0-1 Function Arguments/return values Caller
* x12-17 a2-7 Function arguments Caller
* x18-27 s2-11 Saved registers Callee
* x28-31 t3-6 Temporaries Caller
*
* The RISC-V context is saved RTOS tasks in the following stack frame,
* where the global and thread pointers are currently assumed to be constant so
* are not saved:
*
* mstatus
* #ifndef __riscv_32e
* x31
* x30
* x29
* x28
* x27
* x26
* x25
* x24
* x23
* x22
* x21
* x20
* x19
* x18
* x17
* x16
* #endif
* x15
* x14
* x13
* x12
* x11
* pvParameters
* x9
* x8
* x7
* x6
* x5
* portTASK_RETURN_ADDRESS
* pxCode
*/
StackType_t* pxPortInitialiseStack(StackType_t* pxTopOfStack, TaskFunction_t pxCode, void* pvParameters)
{
/* Simulate the stack frame as it would be created by a context switch
interrupt. */
/* Offset added to account for the way the MCU uses the stack on entry/exit
of interrupts, and to ensure alignment. */
#ifdef CONFIG_RISCV_FPU
pxTopOfStack -= 20;
#endif
pxTopOfStack--;
*pxTopOfStack = portINITIAL_MSTATUS; /* MSTATUS */
/* Save code space by skipping register initialisation. */
#ifndef __riscv_32e
pxTopOfStack -= 22; /* X11 - X31. */
#else
pxTopOfStack -= 6; /* X11 - X15. */
#endif
*pxTopOfStack = (StackType_t) pvParameters; /* X10/A0 */
pxTopOfStack -= 6; /* X5 - X9 */
*pxTopOfStack = (StackType_t) portTASK_RETURN_ADDRESS; /* RA, X1 */
pxTopOfStack --;
*pxTopOfStack = ((StackType_t) pxCode) ; /* PC */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
static void prvTaskExitError(void)
{
volatile uint32_t ulDummy = 0;
/* A function that implements a task must not exit or attempt to return to
its caller as there is nothing to return to. If a task wants to exit it
should instead call vTaskDelete( NULL ).
Artificially force an assert() to be triggered if configASSERT() is
defined, then stop here so application writers can catch the error. */
configASSERT(portGET_CRITICAL_NESTING_COUNT() == ~0UL);
portDISABLE_INTERRUPTS();
while (ulDummy == 0) {
/* This file calls prvTaskExitError() after the scheduler has been
started to remove a compiler warning about the function being defined
but never called. ulDummy is used purely to quieten other warnings
about code appearing after this function is called - making ulDummy
volatile makes the compiler think the function could return and
therefore not output an 'unreachable code' warning for code that appears
after it. */
/* Sleep and wait for interrupt */
__WFI();
}
}
/*-----------------------------------------------------------*/
static uint8_t prvCheckMaxSysCallPrio(uint8_t max_syscall_prio)
{
uint8_t nlbits = __ECLIC_GetCfgNlbits();
uint8_t intctlbits = __ECLIC_INTCTLBITS;
uint8_t lvlbits, temp;
if (nlbits <= intctlbits) {
lvlbits = nlbits;
} else {
lvlbits = intctlbits;
}
temp = ((1 << lvlbits) - 1);
if (max_syscall_prio > temp) {
max_syscall_prio = temp;
}
return max_syscall_prio;
}
static uint8_t prvCalcMaxSysCallMTH(uint8_t max_syscall_prio)
{
uint8_t nlbits = __ECLIC_GetCfgNlbits();
uint8_t intctlbits = __ECLIC_INTCTLBITS;
uint8_t lvlbits, lfabits;
uint8_t maxsyscallmth = 0;
uint8_t temp;
if (nlbits <= intctlbits) {
lvlbits = nlbits;
} else {
lvlbits = intctlbits;
}
lfabits = 8 - lvlbits;
temp = ((1 << lvlbits) - 1);
if (max_syscall_prio > temp) {
max_syscall_prio = temp;
}
maxsyscallmth = (max_syscall_prio << lfabits) | ((1 << lfabits) - 1);
return maxsyscallmth;
}
/*
* See header file for description.
*/
BaseType_t xPortStartScheduler(void)
{
/* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. */
configASSERT(configMAX_SYSCALL_INTERRUPT_PRIORITY);
/* Get the real MTH should be set to ECLIC MTH register */
uxMaxSysCallMTH = prvCalcMaxSysCallMTH(configMAX_SYSCALL_INTERRUPT_PRIORITY);
FREERTOS_PORT_DEBUG("Max SysCall MTH is set to 0x%x\n", uxMaxSysCallMTH);
#if( configASSERT_DEFINED == 1 )
{
/* Use the same mask on the maximum system call priority. */
ucMaxSysCallPriority = prvCheckMaxSysCallPrio(configMAX_SYSCALL_INTERRUPT_PRIORITY);
FREERTOS_PORT_DEBUG("Max SysCall Priority is set to %d\n", ucMaxSysCallPriority);
}
#endif /* conifgASSERT_DEFINED */
__disable_irq();
/* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */
vPortSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
portSET_CRITICAL_NESTING_COUNT(0);
/* Initialise base priority to zero. */
vPortSetBASEPRI(0);
/* Start the first task. */
prvPortStartFirstTask();
/* Should never get here as the tasks will now be executing! Call the task
exit error function to prevent compiler warnings about a static function
not being called in the case that the application writer overrides this
functionality by defining configTASK_RETURN_ADDRESS. Call
vTaskSwitchContext() so link time optimisation does not remove the
symbol. */
vTaskSwitchContext();
prvTaskExitError();
/* Should not get here! */
return 0;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler(void)
{
/* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */
configASSERT(portGET_CRITICAL_NESTING_COUNT() == 1000UL);
}
/*-----------------------------------------------------------*/
_FAST_FUNC_SRAM void vPortEnterCritical(void)
{
portDISABLE_INTERRUPTS();
portINCREMENT_CRITICAL_NESTING_COUNT();
/* This is not the interrupt safe version of the enter critical function so
assert() if it is being called from an interrupt context. Only API
functions that end in "FromISR" can be used in an interrupt. Only assert if
the critical nesting count is 1 to protect against recursive calls if the
assert function also uses a critical section. */
if (portGET_CRITICAL_NESTING_COUNT() == 1) {
configASSERT((__ECLIC_GetMth() & portMTH_MASK) == uxMaxSysCallMTH);
}
}
/*-----------------------------------------------------------*/
_FAST_FUNC_SRAM void vPortExitCritical(void)
{
configASSERT(portGET_CRITICAL_NESTING_COUNT());
portDECREMENT_CRITICAL_NESTING_COUNT();
if (portGET_CRITICAL_NESTING_COUNT() == 0) {
portENABLE_INTERRUPTS();
}
}
/*-----------------------------------------------------------*/
/* Called within Wifi specific MACRO GLOBAL_INT_DISABLE
(as using FreeRTOS macros within wifi stack is not practical) */
void critical_nesting_inc(void)
{
portINCREMENT_CRITICAL_NESTING_COUNT();
}
/* Called within Wifi specific MACRO GLOBAL_INT_RESTORE
(as using FreeRTOS macros within wifi stack is not practical) */
void critical_nesting_dec(void)
{
portDECREMENT_CRITICAL_NESTING_COUNT();
}
void vPortAssert(int32_t x)
{
TaskHandle_t th;
if ((x) == 0) {
taskDISABLE_INTERRUPTS();
#if (INCLUDE_xTaskGetCurrentTaskHandle == 1)
th = xTaskGetCurrentTaskHandle();
if (th) {
printf("Assert in task %s\n", pcTaskGetName(th));
}
#endif
while (1) {
/* Sleep and wait for interrupt */
__WFI();
};
}
}
/*-----------------------------------------------------------*/
void __section(".fast_text") xPortTaskSwitch(void)
{
portDISABLE_INTERRUPTS();
/* Clear Software IRQ, A MUST */
SysTimer_ClearSWIRQ();
vTaskSwitchContext();
portENABLE_INTERRUPTS();
}
/*-----------------------------------------------------------*/
void __section(".fast_text") xPortSysTickHandler(void)
{
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
executes all interrupts must be unmasked. There is therefore no need to
save and then restore the interrupt mask value as its value is already
known. */
portDISABLE_INTERRUPTS();
{
SysTick_Reload(SYSTICK_TICK_CONST);
/* Increment the RTOS tick. */
if (xTaskIncrementTick() != pdFALSE) {
/* A context switch is required. Context switching is performed in
the SWI interrupt. Pend the SWI interrupt. */
portYIELD();
}
}
portENABLE_INTERRUPTS();
}
/*-----------------------------------------------------------*/
#if configUSE_POSIX_ERRNO == 1
int *__errno(void)
{
extern int FreeRTOS_errno;
return &FreeRTOS_errno;
}
#endif
#if( configUSE_TICKLESS_IDLE == 1 )
__attribute__((weak)) void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime)
{
uint32_t ulReloadValue, ulCompleteTickPeriods, ulCompletedSysTickDecrements;
volatile TickType_t xModifiableIdleTime, xTickCountBeforeSleep, XLastLoadValue;
FREERTOS_PORT_DEBUG("Enter TickLess %d\n", (uint32_t)xExpectedIdleTime);
/* Make sure the SysTick reload value does not overflow the counter. */
if (xExpectedIdleTime > xMaximumPossibleSuppressedTicks) {
xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
}
/* Stop the SysTick momentarily. The time the SysTick is stopped for
is accounted for as best it can be, but using the tickless mode will
inevitably result in some tiny drift of the time maintained by the
kernel with respect to calendar time. */
SysTimer_Stop();
/* Calculate the reload value required to wait xExpectedIdleTime
tick periods. -1 is used because this code will execute part way
through one of the tick periods. */
ulReloadValue = (ulTimerCountsForOneTick * (xExpectedIdleTime - 1UL));
if (ulReloadValue > ulStoppedTimerCompensation) {
ulReloadValue -= ulStoppedTimerCompensation;
}
/* Enter a critical section but don't use the taskENTER_CRITICAL()
method as that will mask interrupts that should exit sleep mode. */
__disable_irq();
/* If a context switch is pending or a task is waiting for the scheduler
to be unsuspended then abandon the low power entry. */
if (eTaskConfirmSleepModeStatus() == eAbortSleep) {
/* Restart from whatever is left in the count register to complete
this tick period. */
/* Restart SysTick. */
SysTimer_Start();
/* Reset the reload register to the value required for normal tick
periods. */
SysTick_Reload(ulTimerCountsForOneTick);
/* Re-enable interrupts - see comments above the cpsid instruction()
above. */
__enable_irq();
} else {
xTickCountBeforeSleep = xTaskGetTickCount();
/* Set the new reload value. */
SysTick_Reload(ulReloadValue);
/* Get System timer load value before sleep */
XLastLoadValue = SysTimer_GetLoadValue();
/* Restart SysTick. */
SysTimer_Start();
ECLIC_EnableIRQ(SysTimer_IRQn);
__RWMB();
/* Sleep until something happens. configPRE_SLEEP_PROCESSING() can
set its parameter to 0 to indicate that its implementation contains
its own wait for interrupt or wait for event instruction, and so wfi
should not be executed again. However, the original expected idle
time variable must remain unmodified, so a copy is taken. */
xModifiableIdleTime = xExpectedIdleTime;
configPRE_SLEEP_PROCESSING(xModifiableIdleTime);
if (xModifiableIdleTime > 0) {
__WFI();
}
configPOST_SLEEP_PROCESSING(xExpectedIdleTime);
/* Re-enable interrupts to allow the interrupt that brought the MCU
out of sleep mode to execute immediately. */
__enable_irq();
/* Make sure interrupt enable is executed */
__RWMB();
__FENCE_I();
__NOP();
/* Disable interrupts again because the clock is about to be stopped
and interrupts that execute while the clock is stopped will increase
any slippage between the time maintained by the RTOS and calendar
time. */
__disable_irq();
/* Disable the SysTick clock. Again,
the time the SysTick is stopped for is accounted for as best it can
be, but using the tickless mode will inevitably result in some tiny
drift of the time maintained by the kernel with respect to calendar
time*/
ECLIC_DisableIRQ(SysTimer_IRQn);
/* Determine if SysTimer Interrupt is not yet happened,
(in which case an interrupt other than the SysTick
must have brought the system out of sleep mode). */
if (SysTimer_GetLoadValue() >= (XLastLoadValue + ulReloadValue)) {
/* As the pending tick will be processed as soon as this
function exits, the tick value maintained by the tick is stepped
forward by one less than the time spent waiting. */
ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
FREERTOS_PORT_DEBUG("TickLess - SysTimer Interrupt Entered!\n");
} else {
/* Something other than the tick interrupt ended the sleep.
Work out how long the sleep lasted rounded to complete tick
periods (not the ulReload value which accounted for part
ticks). */
xModifiableIdleTime = SysTimer_GetLoadValue();
if (xModifiableIdleTime > XLastLoadValue) {
ulCompletedSysTickDecrements = (xModifiableIdleTime - XLastLoadValue);
} else {
ulCompletedSysTickDecrements = (xModifiableIdleTime + portMAX_BIT_NUMBER - XLastLoadValue);
}
/* How many complete tick periods passed while the processor
was waiting? */
ulCompleteTickPeriods = ulCompletedSysTickDecrements / ulTimerCountsForOneTick;
/* The reload value is set to whatever fraction of a single tick
period remains. */
SysTick_Reload(ulTimerCountsForOneTick);
FREERTOS_PORT_DEBUG("TickLess - External Interrupt Happened!\n");
}
FREERTOS_PORT_DEBUG("End TickLess %d\n", (uint32_t)ulCompleteTickPeriods);
/* Restart SysTick */
vTaskStepTick(ulCompleteTickPeriods);
/* Exit with interrupts enabled. */
ECLIC_EnableIRQ(SysTimer_IRQn);
__enable_irq();
}
}
#endif /* #if configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/
/*
* Setup the systick timer to generate the tick interrupts at the required
* frequency.
*/
__attribute__((weak)) void vPortSetupTimerInterrupt(void)
{
/* Calculate the constants required to configure the tick interrupt. */
#if( configUSE_TICKLESS_IDLE == 1 )
{
ulTimerCountsForOneTick = (SYSTICK_TICK_CONST);
xMaximumPossibleSuppressedTicks = portMAX_BIT_NUMBER / ulTimerCountsForOneTick;
ulStoppedTimerCompensation = portMISSED_COUNTS_FACTOR / (configCPU_CLOCK_HZ / configSYSTICK_CLOCK_HZ);
FREERTOS_PORT_DEBUG("CountsForOneTick, SuppressedTicks and TimerCompensation: %u, %u, %u\n", \
(uint32_t)ulTimerCountsForOneTick, (uint32_t)xMaximumPossibleSuppressedTicks, (uint32_t)ulStoppedTimerCompensation);
}
#endif /* configUSE_TICKLESS_IDLE */
TickType_t ticks = SYSTICK_TICK_CONST;
/* Make SWI and SysTick the lowest priority interrupts. */
/* Stop and clear the SysTimer. SysTimer as Non-Vector Interrupt */
SysTick_Config(ticks);
ECLIC_DisableIRQ(SysTimer_IRQn);
ECLIC_SetLevelIRQ(SysTimer_IRQn, configKERNEL_INTERRUPT_PRIORITY);
ECLIC_SetShvIRQ(SysTimer_IRQn, ECLIC_NON_VECTOR_INTERRUPT);
ECLIC_EnableIRQ(SysTimer_IRQn);
/* Set SWI interrupt level to lowest level/priority, SysTimerSW as Vector Interrupt */
ECLIC_SetShvIRQ(SysTimerSW_IRQn, ECLIC_VECTOR_INTERRUPT);
ECLIC_SetLevelIRQ(SysTimerSW_IRQn, configKERNEL_INTERRUPT_PRIORITY);
ECLIC_EnableIRQ(SysTimerSW_IRQn);
}
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
#if( configASSERT_DEFINED == 1 )
void vPortValidateInterruptPriority(void)
{
uint32_t ulCurrentInterrupt;
uint8_t ucCurrentPriority;
/* Obtain the number of the currently executing interrupt. */
CSR_MCAUSE_Type mcause = (CSR_MCAUSE_Type)__RV_CSR_READ(CSR_MCAUSE);
/* Make sure current trap type is interrupt */
configASSERT(mcause.b.interrupt == 1);
if (mcause.b.interrupt) {
ulCurrentInterrupt = mcause.b.exccode;
/* Is the interrupt number a user defined interrupt? */
if (ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER) {
/* Look up the interrupt's priority. */
ucCurrentPriority = __ECLIC_GetLevelIRQ(ulCurrentInterrupt);
/* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above
ucMaxSysCallPriority calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below
ucMaxSysCallPriority.
Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than
ucMaxSysCallPriority.
Interrupts that use the FreeRTOS API must not be left at their
default priority of zero as that is the highest possible priority,
which is guaranteed to be above ucMaxSysCallPriority,
and therefore also guaranteed to be invalid.
FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible.
The following links provide detailed information:
http://www.freertos.org/FAQHelp.html */
configASSERT(ucCurrentPriority <= ucMaxSysCallPriority);
}
}
}
#endif /* configASSERT_DEFINED */
/* This variable should not be set in any of the FreeRTOS application
only used internal of FreeRTOS Port code */
extern uint8_t uxMaxSysCallMTH;
/*-----------------------------------------------------------*/
portFORCE_INLINE void vPortRaiseBASEPRI(void)
{
ECLIC_SetMth(uxMaxSysCallMTH);
__RWMB();
}
/*-----------------------------------------------------------*/
portFORCE_INLINE uint8_t ulPortRaiseBASEPRI(void)
{
uint8_t ulOriginalBASEPRI;
ulOriginalBASEPRI = ECLIC_GetMth();
ECLIC_SetMth(uxMaxSysCallMTH);
__RWMB();
/* This return might not be reached but is necessary to prevent compiler
warnings. */
return ulOriginalBASEPRI;
}
/*-----------------------------------------------------------*/
portFORCE_INLINE void vPortSetBASEPRI(uint8_t ulNewMaskValue)
{
ECLIC_SetMth(ulNewMaskValue);
__RWMB();
}
/*-----------------------------------------------------------*/
/* We use this API to determine whether we are currently in an ISR context.
* @ARM: On the ARM platform, we can simply check the IPSR(Interrupt Program Status Register)
* register to determine whether we are in thread mode or interrupt mode.
* @RISCV: On the RISC-V platform, we need to check the TYP bit of the MSUBM(Machine Sub Mode)
* register to identify the current machine sub-mode:
* > 0 indicates Non-Trap Mode;
* > 1 indicates Interrupt Mode;
* > 2 indicates Exception Mode;
* > 3 indicates NMI(Non-Maskable Interrupt) Mode.
* Here, we regards all the modes with none-zero code as ISR context.
* Noted by xhtan@listenai.com
*/
portFORCE_INLINE BaseType_t xPortIsInsideInterrupt( void )
{
return (CSR_MSUBM_Type){.d=__RV_CSR_READ(CSR_MSUBM)}.b.typ;
}
/*-----------------------------------------------------------*/
/* 检测是否在临界区内(通过 MTH 寄存器判断)
* @retval 0 不在临界区
* @retval 1 在临界区
*/
BaseType_t xPortIsInsideCritical( void )
{
return (ECLIC_GetMth() == uxMaxSysCallMTH);
}
void vPortYield()
{ /* Set a software interrupt(SWI) request to request a context switch. */
SysTimer_SetSWIRQ(); /* Barriers are normally not required but do ensure the code is completely \
within the specified behaviour for the architecture. */
__RWMB();
}
uint64_t ulPortGetRunTimeCounterValue(void)
{
return SysTimer_GetLoadValue();
}
__attribute__((weak)) void vPortCleanUpTCB(void *pxTCB)
{
/**
* The Lisa porting layer will use strong symbols instead
*/
}

View File

@@ -0,0 +1,592 @@
/*
* FreeRTOS Kernel V11.1.0
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* The FreeRTOS kernel's RISC-V port is split between the the code that is
* common across all currently supported RISC-V chips (implementations of the
* RISC-V ISA), and code which tailors the port to a specific RISC-V chip:
*
* + The code that is common to all RISC-V chips is implemented in
* FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S. There is only one
* portASM.S file because the same file is used no matter which RISC-V chip is
* in use.
*
* + The code that tailors the kernel's RISC-V port to a specific RISC-V
* chip is implemented in freertos_risc_v_chip_specific_extensions.h. There
* is one freertos_risc_v_chip_specific_extensions.h that can be used with any
* RISC-V chip that both includes a standard CLINT and does not add to the
* base set of RISC-V registers. There are additional
* freertos_risc_v_chip_specific_extensions.h files for RISC-V implementations
* that do not include a standard CLINT or do add to the base set of RISC-V
* registers.
*
* CARE MUST BE TAKEN TO INCLDUE THE CORRECT
* freertos_risc_v_chip_specific_extensions.h HEADER FILE FOR THE CHIP
* IN USE. To include the correct freertos_risc_v_chip_specific_extensions.h
* header file ensure the path to the correct header file is in the assembler's
* include path.
*
* This freertos_risc_v_chip_specific_extensions.h is for use on RISC-V chips
* that include a standard CLINT and do not add to the base set of RISC-V
* registers.
*
*/
#include "riscv_encoding.h"
#ifndef __riscv_32e
#define portRegNum 30
#else
#define portRegNum 14
#endif
#define portCONTEXT_SIZE ( portRegNum * REGBYTES )
#ifdef CONFIG_RISCV_FPU
#define portCONTEXT_SIZE_FPU ( 20 * REGBYTES )
#endif
.section .text.entry
.align 8
.extern xPortTaskSwitch
.extern pxCurrentTCB
.global prvPortStartFirstTask
#if CONFIG_FREERTOS_STACK_HW_CHECK
.extern ulStackTop
.extern ulStackBottom
#endif
/**
* \brief Global interrupt disabled
* \details
* This function disable global interrupt.
* \remarks
* - All the interrupt requests will be ignored by CPU.
*/
.macro DISABLE_MIE
csrc CSR_MSTATUS, MSTATUS_MIE
.endm
/**
* \brief Macro for context save
* \details
* This macro save ABI defined caller saved registers in the stack.
* \remarks
* - This Macro could use to save context when you enter to interrupt
* or exception
*/
/* Save caller registers */
.macro SAVE_CONTEXT
csrrw sp, CSR_MSCRATCH, sp
/* Allocate stack space for context saving */
#ifndef __riscv_32e
addi sp, sp, -20*REGBYTES
#else
addi sp, sp, -14*REGBYTES
#endif /* __riscv_32e */
STORE x1, 0*REGBYTES(sp)
STORE x4, 1*REGBYTES(sp)
STORE x5, 2*REGBYTES(sp)
STORE x6, 3*REGBYTES(sp)
STORE x7, 4*REGBYTES(sp)
STORE x10, 5*REGBYTES(sp)
STORE x11, 6*REGBYTES(sp)
STORE x12, 7*REGBYTES(sp)
STORE x13, 8*REGBYTES(sp)
STORE x14, 9*REGBYTES(sp)
STORE x15, 10*REGBYTES(sp)
#ifndef __riscv_32e
STORE x16, 14*REGBYTES(sp)
STORE x17, 15*REGBYTES(sp)
STORE x28, 16*REGBYTES(sp)
STORE x29, 17*REGBYTES(sp)
STORE x30, 18*REGBYTES(sp)
STORE x31, 19*REGBYTES(sp)
#endif /* __riscv_32e */
.endm
/**
* \brief Macro for restore caller registers
* \details
* This macro restore ABI defined caller saved registers from stack.
* \remarks
* - You could use this macro to restore context before you want return
* from interrupt or exeception
*/
/* Restore caller registers */
.macro RESTORE_CONTEXT
LOAD x1, 0*REGBYTES(sp)
LOAD x4, 1*REGBYTES(sp)
LOAD x5, 2*REGBYTES(sp)
LOAD x6, 3*REGBYTES(sp)
LOAD x7, 4*REGBYTES(sp)
LOAD x10, 5*REGBYTES(sp)
LOAD x11, 6*REGBYTES(sp)
LOAD x12, 7*REGBYTES(sp)
LOAD x13, 8*REGBYTES(sp)
LOAD x14, 9*REGBYTES(sp)
LOAD x15, 10*REGBYTES(sp)
#ifndef __riscv_32e
LOAD x16, 14*REGBYTES(sp)
LOAD x17, 15*REGBYTES(sp)
LOAD x28, 16*REGBYTES(sp)
LOAD x29, 17*REGBYTES(sp)
LOAD x30, 18*REGBYTES(sp)
LOAD x31, 19*REGBYTES(sp)
/* De-allocate the stack space */
addi sp, sp, 20*REGBYTES
#else
/* De-allocate the stack space */
addi sp, sp, 14*REGBYTES
#endif /* __riscv_32e */
csrrw sp, CSR_MSCRATCH, sp
.endm
/**
* \brief Macro for save necessary CSRs to stack
* \details
* This macro store MCAUSE, MEPC, MSUBM to stack.
*/
.macro SAVE_CSR_CONTEXT
/* Store CSR mcause to stack using pushmcause */
csrrwi x0, CSR_PUSHMCAUSE, 11
/* Store CSR mepc to stack using pushmepc */
csrrwi x0, CSR_PUSHMEPC, 12
/* Store CSR msub to stack using pushmsub */
csrrwi x0, CSR_PUSHMSUBM, 13
.endm
/**
* \brief Macro for restore necessary CSRs from stack
* \details
* This macro restore MSUBM, MEPC, MCAUSE from stack.
*/
.macro RESTORE_CSR_CONTEXT
LOAD x5, 13*REGBYTES(sp)
csrw CSR_MSUBM, x5
LOAD x5, 12*REGBYTES(sp)
csrw CSR_MEPC, x5
LOAD x5, 11*REGBYTES(sp)
csrw CSR_MCAUSE, x5
.endm
/**
* \brief Exception/NMI Entry
* \details
* This function provide common entry functions for exception/nmi.
* \remarks
* This function provide a default exception/nmi entry.
* ABI defined caller save register and some CSR registers
* to be saved before enter interrupt handler and be restored before return.
*/
.section .text.trap
/* In CLIC mode, the exeception entry must be 64bytes aligned */
.align 6
.global exc_entry
.type exc_entry, @function
exc_entry:
#if CONFIG_FREERTOS_STACK_HW_CHECK
/* 关闭硬件栈溢出检测 */
csrw mstack_ctl, 0x0
#endif
/* Save the caller saving registers (context) */
csrrw sp, CSR_MSCRATCH, sp
/* Allocate stack space for context saving */
#ifndef __riscv_32e
/* 让sp进行16字节地址对齐, 否则浮点运行会异常 */
addi sp, sp, -40*REGBYTES
#else
addi sp, sp, -20*REGBYTES
#endif /* __riscv_32e */
STORE x0, 0*REGBYTES(sp)
STORE x1, 1*REGBYTES(sp)
/* x2/sp寄存器等t0寄存器保存后在保存 */
STORE x3, 3*REGBYTES(sp)
STORE x4, 4*REGBYTES(sp)
/* 保存t0寄存器 */
STORE x5, 5*REGBYTES(sp)
/* 读取之前的SP到t0中 */
csrr t0, mscratch
/* 将保存到sp */
STORE t0, 2*REGBYTES(sp)
STORE x6, 6*REGBYTES(sp)
STORE x7, 7*REGBYTES(sp)
STORE x8, 8*REGBYTES(sp)
STORE x9, 9*REGBYTES(sp)
STORE x10, 10*REGBYTES(sp)
STORE x11, 11*REGBYTES(sp)
STORE x12, 12*REGBYTES(sp)
STORE x13, 13*REGBYTES(sp)
STORE x14, 14*REGBYTES(sp)
STORE x15, 15*REGBYTES(sp)
#ifndef __riscv_32e
STORE x16, 16*REGBYTES(sp)
STORE x17, 17*REGBYTES(sp)
STORE x18, 18*REGBYTES(sp)
STORE x19, 19*REGBYTES(sp)
STORE x20, 20*REGBYTES(sp)
STORE x21, 21*REGBYTES(sp)
STORE x22, 22*REGBYTES(sp)
STORE x23, 23*REGBYTES(sp)
STORE x24, 24*REGBYTES(sp)
STORE x25, 25*REGBYTES(sp)
STORE x26, 26*REGBYTES(sp)
STORE x27, 27*REGBYTES(sp)
STORE x28, 28*REGBYTES(sp)
STORE x29, 29*REGBYTES(sp)
STORE x30, 30*REGBYTES(sp)
STORE x31, 31*REGBYTES(sp)
csrr t0, mcause
STORE t0, 32*REGBYTES(sp)
csrr t0, mepc
STORE t0, 33*REGBYTES(sp)
csrr t0, msubm
STORE t0, 34*REGBYTES(sp)
#else
csrr t0, mcause
STORE t0, 16*REGBYTES(sp)
csrr t0, mepc
STORE t0, 17*REGBYTES(sp)
csrr t0, msubm
STORE t0, 18*REGBYTES(sp)
#endif /* __riscv_32e */
/*
* Set the exception handler function arguments
* argument 1: mcause value
* argument 2: current stack point(SP) value
*/
csrr a0, mcause
mv a1, sp
/*
* TODO: Call the exception handler function
* By default, the function template is provided in
* system_Device.c, you can adjust it as you want
*/
call core_exception_handler
/* Restore the necessary CSR registers */
RESTORE_CSR_CONTEXT
/* Restore the caller saving registers (context) */
RESTORE_CONTEXT
/* Return to regular code */
mret
.size exc_entry, . - exc_entry
/**
* \brief Non-Vector Interrupt Entry
* \details
* This function provide common entry functions for handling
* non-vector interrupts
* \remarks
* This function provide a default non-vector interrupt entry.
* ABI defined caller save register and some CSR registers need
* to be saved before enter interrupt handler and be restored before return.
*/
.section .text.irq
/* In CLIC mode, the interrupt entry must be 4bytes aligned */
.align 2
.global irq_entry
.type irq_entry, @function
/* This label will be set to MTVT2 register */
irq_entry:
#if CONFIG_FREERTOS_STACK_HW_CHECK
/* 关闭硬件栈溢出检测 */
csrw mstack_ctl, 0x0
#endif
/* Save the caller saving registers (context) */
SAVE_CONTEXT
/* Save the necessary CSR registers */
SAVE_CSR_CONTEXT
/* This special CSR read/write operation, which is actually
* claim the CLIC to find its pending highest ID, if the ID
* is not 0, then automatically enable the mstatus.MIE, and
* jump to its vector-entry-label, and update the link register
*/
csrrw ra, CSR_JALMNXTI, ra
/* Critical section with interrupts disabled */
DISABLE_MIE
/* Restore the necessary CSR registers */
RESTORE_CSR_CONTEXT
/* Restore the caller saving registers (context) */
RESTORE_CONTEXT
/* Return to regular code */
mret
.size irq_entry, . - irq_entry
/* Default Handler for Exceptions / Interrupts */
.global default_intexc_handler
.type default_intexc_handler, @function
default_intexc_handler:
1:
j 1b
.size default_intexc_handler, . - default_intexc_handler
/* Start the first task. This also clears the bit that indicates the FPU is
in use in case the FPU was used before the scheduler was started - which
would otherwise result in the unnecessary leaving of space in the stack
for lazy saving of FPU registers. */
.section .text
.type prvPortStartFirstTask, @function
.align 3
prvPortStartFirstTask:
/* Setup Interrupt Stack using
The stack that was used by main()
before the scheduler is started is
no longer required after the scheduler is started.
Interrupt stack pointer is stored in CSR_MSCRATCH */
la t0, __StackTop
csrw CSR_MSCRATCH, t0
LOAD t0, pxCurrentTCB /* Load pxCurrentTCB. */
LOAD sp, 0x0(t0) /* Read sp from first TCB member */
/* Pop PC from stack and set MEPC */
LOAD t0, 0 * REGBYTES(sp)
csrw CSR_MEPC, t0
/* Pop mstatus from stack and set it */
LOAD t0, (portRegNum - 1) * REGBYTES(sp)
csrw CSR_MSTATUS, t0
/* Interrupt still disable here */
/* Restore Registers from Stack */
LOAD x1, 1 * REGBYTES(sp) /* RA */
LOAD x5, 2 * REGBYTES(sp)
LOAD x6, 3 * REGBYTES(sp)
LOAD x7, 4 * REGBYTES(sp)
LOAD x8, 5 * REGBYTES(sp)
LOAD x9, 6 * REGBYTES(sp)
LOAD x10, 7 * REGBYTES(sp)
LOAD x11, 8 * REGBYTES(sp)
LOAD x12, 9 * REGBYTES(sp)
LOAD x13, 10 * REGBYTES(sp)
LOAD x14, 11 * REGBYTES(sp)
LOAD x15, 12 * REGBYTES(sp)
#ifndef __riscv_32e
LOAD x16, 13 * REGBYTES(sp)
LOAD x17, 14 * REGBYTES(sp)
LOAD x18, 15 * REGBYTES(sp)
LOAD x19, 16 * REGBYTES(sp)
LOAD x20, 17 * REGBYTES(sp)
LOAD x21, 18 * REGBYTES(sp)
LOAD x22, 19 * REGBYTES(sp)
LOAD x23, 20 * REGBYTES(sp)
LOAD x24, 21 * REGBYTES(sp)
LOAD x25, 22 * REGBYTES(sp)
LOAD x26, 23 * REGBYTES(sp)
LOAD x27, 24 * REGBYTES(sp)
LOAD x28, 25 * REGBYTES(sp)
LOAD x29, 26 * REGBYTES(sp)
LOAD x30, 27 * REGBYTES(sp)
LOAD x31, 28 * REGBYTES(sp)
#endif
addi sp, sp, portCONTEXT_SIZE
mret
.size prvPortStartFirstTask, . - prvPortStartFirstTask
.section .text.irq
.align 2
.global eclic_msip_handler
.type eclic_msip_handler, @function
eclic_msip_handler:
#if CONFIG_FREERTOS_STACK_HW_CHECK
/* 关闭硬件栈溢出检测 */
csrw mstack_ctl, 0x0
#endif
#ifdef CONFIG_RISCV_FPU
/* Push additional registers */
addi sp, sp, -portCONTEXT_SIZE_FPU
FPSTORE ft0, 0 * REGBYTES(sp) /* FT0 */
FPSTORE ft1, 1 * REGBYTES(sp) /* FT1 */
FPSTORE ft2, 2 * REGBYTES(sp) /* FT2 */
FPSTORE ft3, 3 * REGBYTES(sp) /* FT3 */
FPSTORE ft4, 4 * REGBYTES(sp) /* FT4 */
FPSTORE ft5, 5 * REGBYTES(sp) /* FT5 */
FPSTORE ft6, 6 * REGBYTES(sp) /* FT6 */
FPSTORE ft7, 7 * REGBYTES(sp) /* FT7 */
FPSTORE fa0, 8 * REGBYTES(sp) /* FA0 */
FPSTORE fa1, 9 * REGBYTES(sp) /* FA1 */
FPSTORE fa2, 10 * REGBYTES(sp) /* FA2 */
FPSTORE fa3, 11 * REGBYTES(sp) /* FA3 */
FPSTORE fa4, 12 * REGBYTES(sp) /* FA4 */
FPSTORE fa5, 13 * REGBYTES(sp) /* FA5 */
FPSTORE fa6, 14 * REGBYTES(sp) /* FA6 */
FPSTORE fa7, 15 * REGBYTES(sp) /* FA7 */
FPSTORE ft8, 16 * REGBYTES(sp) /* FT8 */
FPSTORE ft9, 17 * REGBYTES(sp) /* FT9 */
FPSTORE ft10, 18 * REGBYTES(sp) /* FT10 */
FPSTORE ft11, 19 * REGBYTES(sp) /* FT11 */
#endif
addi sp, sp, -portCONTEXT_SIZE
STORE x1, 1 * REGBYTES(sp) /* RA */
STORE x5, 2 * REGBYTES(sp)
STORE x6, 3 * REGBYTES(sp)
STORE x7, 4 * REGBYTES(sp)
STORE x8, 5 * REGBYTES(sp)
STORE x9, 6 * REGBYTES(sp)
STORE x10, 7 * REGBYTES(sp)
STORE x11, 8 * REGBYTES(sp)
STORE x12, 9 * REGBYTES(sp)
STORE x13, 10 * REGBYTES(sp)
STORE x14, 11 * REGBYTES(sp)
STORE x15, 12 * REGBYTES(sp)
#ifndef __riscv_32e
STORE x16, 13 * REGBYTES(sp)
STORE x17, 14 * REGBYTES(sp)
STORE x18, 15 * REGBYTES(sp)
STORE x19, 16 * REGBYTES(sp)
STORE x20, 17 * REGBYTES(sp)
STORE x21, 18 * REGBYTES(sp)
STORE x22, 19 * REGBYTES(sp)
STORE x23, 20 * REGBYTES(sp)
STORE x24, 21 * REGBYTES(sp)
STORE x25, 22 * REGBYTES(sp)
STORE x26, 23 * REGBYTES(sp)
STORE x27, 24 * REGBYTES(sp)
STORE x28, 25 * REGBYTES(sp)
STORE x29, 26 * REGBYTES(sp)
STORE x30, 27 * REGBYTES(sp)
STORE x31, 28 * REGBYTES(sp)
#endif
/* Push mstatus to stack */
csrr t0, CSR_MSTATUS
STORE t0, (portRegNum - 1) * REGBYTES(sp)
/* Push additional registers */
/* Store sp to task stack */
LOAD t0, pxCurrentTCB /* Load pxCurrentTCB. */
STORE sp, 0(t0)
csrr t0, CSR_MEPC
STORE t0, 0(sp)
jal xPortTaskSwitch
/* Switch task context */
LOAD t0, pxCurrentTCB /* Load pxCurrentTCB. */
LOAD sp, 0x0(t0) /* Read sp from first TCB member */
#if CONFIG_FREERTOS_STACK_HW_CHECK
/* 开启硬件栈保护 */
LOAD t0, ulStackTop
csrw mstack_base, t0
LOAD t0, ulStackBottom
csrw mstack_bound, t0
csrw mstack_ctl, 0x3
#endif
/* Pop PC from stack and set MEPC */
LOAD t0, 0 * REGBYTES(sp)
csrw CSR_MEPC, t0
/* Pop additional registers */
/* Pop mstatus from stack and set it */
LOAD t0, (portRegNum - 1) * REGBYTES(sp)
csrw CSR_MSTATUS, t0
/* Interrupt still disable here */
/* Restore Registers from Stack */
LOAD x1, 1 * REGBYTES(sp) /* RA */
LOAD x5, 2 * REGBYTES(sp)
LOAD x6, 3 * REGBYTES(sp)
LOAD x7, 4 * REGBYTES(sp)
LOAD x8, 5 * REGBYTES(sp)
LOAD x9, 6 * REGBYTES(sp)
LOAD x10, 7 * REGBYTES(sp)
LOAD x11, 8 * REGBYTES(sp)
LOAD x12, 9 * REGBYTES(sp)
LOAD x13, 10 * REGBYTES(sp)
LOAD x14, 11 * REGBYTES(sp)
LOAD x15, 12 * REGBYTES(sp)
#ifndef __riscv_32e
LOAD x16, 13 * REGBYTES(sp)
LOAD x17, 14 * REGBYTES(sp)
LOAD x18, 15 * REGBYTES(sp)
LOAD x19, 16 * REGBYTES(sp)
LOAD x20, 17 * REGBYTES(sp)
LOAD x21, 18 * REGBYTES(sp)
LOAD x22, 19 * REGBYTES(sp)
LOAD x23, 20 * REGBYTES(sp)
LOAD x24, 21 * REGBYTES(sp)
LOAD x25, 22 * REGBYTES(sp)
LOAD x26, 23 * REGBYTES(sp)
LOAD x27, 24 * REGBYTES(sp)
LOAD x28, 25 * REGBYTES(sp)
LOAD x29, 26 * REGBYTES(sp)
LOAD x30, 27 * REGBYTES(sp)
LOAD x31, 28 * REGBYTES(sp)
#endif
addi sp, sp, portCONTEXT_SIZE
#ifdef CONFIG_RISCV_FPU
/* Pop additional registers */
FPLOAD ft0, 0 * REGBYTES(sp) /* FT0 */
FPLOAD ft1, 1 * REGBYTES(sp) /* FT1 */
FPLOAD ft2, 2 * REGBYTES(sp) /* FT2 */
FPLOAD ft3, 3 * REGBYTES(sp) /* FT3 */
FPLOAD ft4, 4 * REGBYTES(sp) /* FT4 */
FPLOAD ft5, 5 * REGBYTES(sp) /* FT5 */
FPLOAD ft6, 6 * REGBYTES(sp) /* FT6 */
FPLOAD ft7, 7 * REGBYTES(sp) /* FT7 */
FPLOAD fa0, 8 * REGBYTES(sp) /* FA0 */
FPLOAD fa1, 9 * REGBYTES(sp) /* FA1 */
FPLOAD fa2, 10 * REGBYTES(sp) /* FA2 */
FPLOAD fa3, 11 * REGBYTES(sp) /* FA3 */
FPLOAD fa4, 12 * REGBYTES(sp) /* FA4 */
FPLOAD fa5, 13 * REGBYTES(sp) /* FA5 */
FPLOAD fa6, 14 * REGBYTES(sp) /* FA6 */
FPLOAD fa7, 15 * REGBYTES(sp) /* FA7 */
FPLOAD ft8, 16 * REGBYTES(sp) /* FT8 */
FPLOAD ft9, 17 * REGBYTES(sp) /* FT9 */
FPLOAD ft10, 18 * REGBYTES(sp) /* FT10 */
FPLOAD ft11, 19 * REGBYTES(sp) /* FT11 */
addi sp, sp, portCONTEXT_SIZE_FPU
#endif
mret
.size eclic_msip_handler, . - eclic_msip_handler

View File

@@ -0,0 +1,19 @@
Each real time kernel port consists of three files that contain the core kernel
components and are common to every port, and one or more files that are
specific to a particular microcontroller and/or compiler.
+ The FreeRTOS/Source/Portable/MemMang directory contains the five sample
memory allocators as described on the https://www.FreeRTOS.org WEB site.
+ The other directories each contain files specific to a particular
microcontroller or compiler, where the directory name denotes the compiler
specific files the directory contains.
For example, if you are interested in the [compiler] port for the [architecture]
microcontroller, then the port specific files are contained in
FreeRTOS/Source/Portable/[compiler]/[architecture] directory. If this is the
only port you are interested in then all the other directories can be
ignored.