mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-04-20 05:21:59 -04:00
Enhance heap_4.c to prevent blocks accidentally being freed twice, or blocks that don't have a valid block link descriptor being freed.
Update the Cortex-A9 port to include asserts if an ISR safe FreeRTOS function is called from an interrupt that has a higher logical priority than configMAX_SYSCALL_INTERRUPT_PRIORITY (or whatever the CA9 equivalent is called), and also assert if the binary point is not set correctly.
This commit is contained in:
parent
4894955a08
commit
0f6b0d3a59
|
@ -143,6 +143,10 @@ context. */
|
||||||
#define portINTERRUPT_ENABLE_BIT ( 0x80UL )
|
#define portINTERRUPT_ENABLE_BIT ( 0x80UL )
|
||||||
#define portTHUMB_MODE_ADDRESS ( 0x01UL )
|
#define portTHUMB_MODE_ADDRESS ( 0x01UL )
|
||||||
|
|
||||||
|
/* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
|
||||||
|
point is zero. */
|
||||||
|
#define portBINARY_POINT_BITS ( ( unsigned char ) 0x03 )
|
||||||
|
|
||||||
/* Masks all bits in the APSR other than the mode bits. */
|
/* Masks all bits in the APSR other than the mode bits. */
|
||||||
#define portAPSR_MODE_BITS_MASK ( 0x1F )
|
#define portAPSR_MODE_BITS_MASK ( 0x1F )
|
||||||
|
|
||||||
|
@ -177,11 +181,6 @@ the scheduler starts. As it is stored as part of the task context it will
|
||||||
automatically be set to 0 when the first task is started. */
|
automatically be set to 0 when the first task is started. */
|
||||||
volatile unsigned long ulCriticalNesting = 9999UL;
|
volatile unsigned long ulCriticalNesting = 9999UL;
|
||||||
|
|
||||||
/* The value to be written to the interrupt controllers priority mask register
|
|
||||||
to mask interrupts that can use the FreeRTOS API without masking higher priority
|
|
||||||
interrupts. */
|
|
||||||
const unsigned long ulPortAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
|
|
||||||
|
|
||||||
/* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
|
/* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
|
||||||
a floating point context must be saved and restored for the task. */
|
a floating point context must be saved and restored for the task. */
|
||||||
unsigned long ulPortTaskHasFPUContext = pdFALSE;
|
unsigned long ulPortTaskHasFPUContext = pdFALSE;
|
||||||
|
@ -193,6 +192,7 @@ unsigned long ulPortYieldRequired = pdFALSE;
|
||||||
if the nesting depth is 0. */
|
if the nesting depth is 0. */
|
||||||
unsigned long ulPortInterruptNesting = 0UL;
|
unsigned long ulPortInterruptNesting = 0UL;
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -281,6 +281,13 @@ unsigned long ulAPSR;
|
||||||
configASSERT( ulAPSR != portAPSR_USER_MODE );
|
configASSERT( ulAPSR != portAPSR_USER_MODE );
|
||||||
|
|
||||||
if( ulAPSR != portAPSR_USER_MODE )
|
if( ulAPSR != portAPSR_USER_MODE )
|
||||||
|
{
|
||||||
|
/* Only continue if the binary point value is set to its lowest possible
|
||||||
|
setting. See the comments in vPortValidateInterruptPriority() below for
|
||||||
|
more information. */
|
||||||
|
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
|
||||||
|
|
||||||
|
if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
|
||||||
{
|
{
|
||||||
/* Start the timer that generates the tick ISR. */
|
/* Start the timer that generates the tick ISR. */
|
||||||
configSETUP_TICK_INTERRUPT();
|
configSETUP_TICK_INTERRUPT();
|
||||||
|
@ -288,9 +295,11 @@ unsigned long ulAPSR;
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
vPortRestoreTaskContext();
|
vPortRestoreTaskContext();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Will only get here if xTaskStartScheduler() was called with the CPU in
|
/* Will only get here if xTaskStartScheduler() was called with the CPU in
|
||||||
a non-privileged mode. */
|
a non-privileged mode or the binary point register was not set to its lowest
|
||||||
|
possible value. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
@ -340,7 +349,7 @@ void FreeRTOS_Tick_Handler( void )
|
||||||
handler runs at the lowest priority, so interrupts cannot already be masked,
|
handler runs at the lowest priority, so interrupts cannot already be masked,
|
||||||
so there is no need to save and restore the current mask value. */
|
so there is no need to save and restore the current mask value. */
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask;
|
portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
|
||||||
__asm( "DSB \n"
|
__asm( "DSB \n"
|
||||||
"ISB \n" );
|
"ISB \n" );
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
@ -383,7 +392,7 @@ unsigned long ulPortSetInterruptMask( void )
|
||||||
unsigned long ulReturn;
|
unsigned long ulReturn;
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
if( portICCPMR_PRIORITY_MASK_REGISTER == ulPortAPIPriorityMask )
|
if( portICCPMR_PRIORITY_MASK_REGISTER == ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
|
||||||
{
|
{
|
||||||
/* Interrupts were already masked. */
|
/* Interrupts were already masked. */
|
||||||
ulReturn = pdTRUE;
|
ulReturn = pdTRUE;
|
||||||
|
@ -391,7 +400,7 @@ unsigned long ulReturn;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulReturn = pdFALSE;
|
ulReturn = pdFALSE;
|
||||||
portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask;
|
portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
|
||||||
__asm( "DSB \n"
|
__asm( "DSB \n"
|
||||||
"ISB \n" );
|
"ISB \n" );
|
||||||
}
|
}
|
||||||
|
@ -399,5 +408,45 @@ unsigned long ulReturn;
|
||||||
|
|
||||||
return ulReturn;
|
return ulReturn;
|
||||||
}
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( configASSERT_DEFINED == 1 )
|
||||||
|
|
||||||
|
void vPortValidateInterruptPriority( void )
|
||||||
|
{
|
||||||
|
/* The following assertion will fail if a service routine (ISR) for
|
||||||
|
an interrupt that has been assigned a priority above
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY 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
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY.
|
||||||
|
|
||||||
|
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
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY.
|
||||||
|
|
||||||
|
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/RTOS-Cortex-M3-M4.html
|
||||||
|
http://www.freertos.org/FAQHelp.html */
|
||||||
|
configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
|
||||||
|
|
||||||
|
/* Priority grouping: The interrupt controller (GIC) allows the bits
|
||||||
|
that define each interrupt's priority to be split between bits that
|
||||||
|
define the interrupt's pre-emption priority bits and bits that define
|
||||||
|
the interrupt's sub-priority. For simplicity all bits must be defined
|
||||||
|
to be pre-emption priority bits. The following assertion will fail if
|
||||||
|
this is not the case (if some bits represent a sub-priority).
|
||||||
|
|
||||||
|
The priority grouping is configured by the GIC's binary point register
|
||||||
|
(ICCBPR). Writting 0 to ICCBPR will ensure it is set to its lowest
|
||||||
|
possible value (which may be above 0). */
|
||||||
|
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configASSERT_DEFINED */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
|
|
||||||
/* IAR includes. */
|
/* IAR includes. */
|
||||||
#ifdef __ICCARM__
|
#ifdef __ICCARM__
|
||||||
|
|
||||||
#include <intrinsics.h>
|
#include <intrinsics.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -181,27 +182,40 @@ void vPortTaskUsesFPU( void );
|
||||||
|
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
|
|
||||||
|
#ifdef configASSERT
|
||||||
|
void vPortValidateInterruptPriority( void );
|
||||||
|
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
|
||||||
|
#else
|
||||||
|
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define portNOP() __asm volatile( "NOP" )
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __ICCARM__ */
|
#endif /* __ICCARM__ */
|
||||||
|
|
||||||
#define portNOP() __asm volatile( "NOP" )
|
|
||||||
|
|
||||||
|
|
||||||
/* The number of bits to shift for an interrupt priority is dependent on the
|
/* The number of bits to shift for an interrupt priority is dependent on the
|
||||||
number of bits implemented by the interrupt controller. */
|
number of bits implemented by the interrupt controller. */
|
||||||
#if configUNIQUE_INTERRUPT_PRIORITIES == 16
|
#if configUNIQUE_INTERRUPT_PRIORITIES == 16
|
||||||
#define portPRIORITY_SHIFT 4
|
#define portPRIORITY_SHIFT 4
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 3
|
||||||
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32
|
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32
|
||||||
#define portPRIORITY_SHIFT 3
|
#define portPRIORITY_SHIFT 3
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 2
|
||||||
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64
|
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64
|
||||||
#define portPRIORITY_SHIFT 2
|
#define portPRIORITY_SHIFT 2
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 1
|
||||||
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128
|
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128
|
||||||
#define portPRIORITY_SHIFT 1
|
#define portPRIORITY_SHIFT 1
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 0
|
||||||
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256
|
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256
|
||||||
#define portPRIORITY_SHIFT 0
|
#define portPRIORITY_SHIFT 0
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 0
|
||||||
#else
|
#else
|
||||||
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
|
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
|
||||||
#endif
|
#endif
|
||||||
|
@ -210,12 +224,16 @@ number of bits implemented by the interrupt controller. */
|
||||||
#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )
|
#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )
|
||||||
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )
|
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )
|
||||||
#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )
|
#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )
|
||||||
|
#define portICCBPR_BINARY_POINT_OFFSET ( 0x08 )
|
||||||
|
#define portICCRPR_RUNNING_PRIORITY_OFFSET ( 0x14 )
|
||||||
|
|
||||||
#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
|
#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
|
||||||
#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
|
#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile unsigned char * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
|
||||||
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
|
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
|
||||||
#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
|
#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
|
||||||
#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )
|
#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )
|
||||||
|
#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )
|
||||||
|
#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile unsigned char * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )
|
||||||
|
|
||||||
#endif /* PORTMACRO_H */
|
#endif /* PORTMACRO_H */
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,11 @@ task.h is included from an application file. */
|
||||||
/* Block sizes must not get too small. */
|
/* Block sizes must not get too small. */
|
||||||
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
|
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
|
||||||
|
|
||||||
|
/* Assumes 8bit bytes! */
|
||||||
|
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
|
||||||
|
|
||||||
/* A few bytes might be lost to byte aligning the heap start address. */
|
/* A few bytes might be lost to byte aligning the heap start address. */
|
||||||
#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
|
#define heapADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT )
|
||||||
|
|
||||||
/* Allocate the memory for the heap. */
|
/* Allocate the memory for the heap. */
|
||||||
static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];
|
static unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||||
|
@ -132,16 +135,20 @@ block must by correctly byte aligned. */
|
||||||
static const unsigned short heapSTRUCT_SIZE = ( ( sizeof ( xBlockLink ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
|
static const unsigned short heapSTRUCT_SIZE = ( ( sizeof ( xBlockLink ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK );
|
||||||
|
|
||||||
/* Ensure the pxEnd pointer will end up on the correct byte alignment. */
|
/* Ensure the pxEnd pointer will end up on the correct byte alignment. */
|
||||||
static const size_t xTotalHeapSize = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );
|
static const size_t xTotalHeapSize = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );
|
||||||
|
|
||||||
/* Create a couple of list links to mark the start and end of the list. */
|
/* Create a couple of list links to mark the start and end of the list. */
|
||||||
static xBlockLink xStart, *pxEnd = NULL;
|
static xBlockLink xStart, *pxEnd = NULL;
|
||||||
|
|
||||||
/* Keeps track of the number of free bytes remaining, but says nothing about
|
/* Keeps track of the number of free bytes remaining, but says nothing about
|
||||||
fragmentation. */
|
fragmentation. */
|
||||||
static size_t xFreeBytesRemaining = ( ( size_t ) configADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );
|
static size_t xFreeBytesRemaining = ( ( size_t ) heapADJUSTED_HEAP_SIZE ) & ( ( size_t ) ~portBYTE_ALIGNMENT_MASK );
|
||||||
|
|
||||||
/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
|
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
|
||||||
|
member of an xBlockLink 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. */
|
||||||
|
static size_t xBlockAllocatedBit = 0;
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -159,14 +166,20 @@ void *pvReturn = NULL;
|
||||||
prvHeapInit();
|
prvHeapInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 xBlockLink structure
|
||||||
|
is used to determine who owns the block - the application or the
|
||||||
|
kernel, so it must be free. */
|
||||||
|
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
|
||||||
|
{
|
||||||
/* The wanted size is increased so it can contain a xBlockLink
|
/* The wanted size is increased so it can contain a xBlockLink
|
||||||
structure in addition to the requested amount of bytes. */
|
structure in addition to the requested amount of bytes. */
|
||||||
if( xWantedSize > 0 )
|
if( xWantedSize > 0 )
|
||||||
{
|
{
|
||||||
xWantedSize += heapSTRUCT_SIZE;
|
xWantedSize += heapSTRUCT_SIZE;
|
||||||
|
|
||||||
/* Ensure that blocks are always aligned to the required number of
|
/* Ensure that blocks are always aligned to the required number
|
||||||
bytes. */
|
of bytes. */
|
||||||
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
|
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
|
||||||
{
|
{
|
||||||
/* Byte alignment required. */
|
/* Byte alignment required. */
|
||||||
|
@ -174,10 +187,10 @@ void *pvReturn = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ( xWantedSize > 0 ) && ( xWantedSize < xTotalHeapSize ) )
|
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
|
||||||
{
|
{
|
||||||
/* Traverse the list from the start (lowest address) block until one
|
/* Traverse the list from the start (lowest address) block until
|
||||||
of adequate size is found. */
|
one of adequate size is found. */
|
||||||
pxPreviousBlock = &xStart;
|
pxPreviousBlock = &xStart;
|
||||||
pxBlock = xStart.pxNextFreeBlock;
|
pxBlock = xStart.pxNextFreeBlock;
|
||||||
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
|
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
|
||||||
|
@ -186,28 +199,30 @@ void *pvReturn = NULL;
|
||||||
pxBlock = pxBlock->pxNextFreeBlock;
|
pxBlock = pxBlock->pxNextFreeBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the end marker was reached then a block of adequate size was
|
/* If the end marker was reached then a block of adequate size
|
||||||
not found. */
|
was not found. */
|
||||||
if( pxBlock != pxEnd )
|
if( pxBlock != pxEnd )
|
||||||
{
|
{
|
||||||
/* Return the memory space - jumping over the xBlockLink structure
|
/* Return the memory space pointed to - jumping over the
|
||||||
at its start. */
|
xBlockLink structure at its start. */
|
||||||
pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
|
pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
|
||||||
|
|
||||||
/* This block is being returned for use so must be taken out of
|
/* This block is being returned for use so must be taken out
|
||||||
the list of free blocks. */
|
of the list of free blocks. */
|
||||||
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
|
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
|
||||||
|
|
||||||
/* If the block is larger than required it can be split into two. */
|
/* If the block is larger than required it can be split into
|
||||||
|
two. */
|
||||||
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
|
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||||
{
|
{
|
||||||
/* This block is to be split into two. Create a new block
|
/* This block is to be split into two. Create a new
|
||||||
following the number of bytes requested. The void cast is
|
block following the number of bytes requested. The void
|
||||||
used to prevent byte alignment warnings from the compiler. */
|
cast is used to prevent byte alignment warnings from the
|
||||||
|
compiler. */
|
||||||
pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize );
|
pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize );
|
||||||
|
|
||||||
/* Calculate the sizes of two blocks split from the single
|
/* Calculate the sizes of two blocks split from the
|
||||||
block. */
|
single block. */
|
||||||
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
|
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
|
||||||
pxBlock->xBlockSize = xWantedSize;
|
pxBlock->xBlockSize = xWantedSize;
|
||||||
|
|
||||||
|
@ -216,6 +231,12 @@ void *pvReturn = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
xFreeBytesRemaining -= pxBlock->xBlockSize;
|
xFreeBytesRemaining -= pxBlock->xBlockSize;
|
||||||
|
|
||||||
|
/* The block is being returned - it is allocated and owned
|
||||||
|
by the application and has no "next" block. */
|
||||||
|
pxBlock->xBlockSize |= xBlockAllocatedBit;
|
||||||
|
pxBlock->pxNextFreeBlock = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,6 +270,18 @@ xBlockLink *pxLink;
|
||||||
/* This casting is to keep the compiler from issuing warnings. */
|
/* This casting is to keep the compiler from issuing warnings. */
|
||||||
pxLink = ( void * ) puc;
|
pxLink = ( void * ) puc;
|
||||||
|
|
||||||
|
/* Check the block is actually allocated. */
|
||||||
|
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
|
||||||
|
configASSERT( pxLink->pxNextFreeBlock == NULL );
|
||||||
|
|
||||||
|
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
|
||||||
|
{
|
||||||
|
if( pxLink->pxNextFreeBlock == NULL )
|
||||||
|
{
|
||||||
|
/* The block is being returned to the heap - it is no longer
|
||||||
|
allocated. */
|
||||||
|
pxLink->xBlockSize &= ~xBlockAllocatedBit;
|
||||||
|
|
||||||
vTaskSuspendAll();
|
vTaskSuspendAll();
|
||||||
{
|
{
|
||||||
/* Add this block to the list of free blocks. */
|
/* Add this block to the list of free blocks. */
|
||||||
|
@ -258,6 +291,8 @@ xBlockLink *pxLink;
|
||||||
xTaskResumeAll();
|
xTaskResumeAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
size_t xPortGetFreeHeapSize( void )
|
size_t xPortGetFreeHeapSize( void )
|
||||||
|
@ -302,6 +337,9 @@ unsigned char *pucHeapEnd, *pucAlignedHeap;
|
||||||
|
|
||||||
/* The heap now contains pxEnd. */
|
/* The heap now contains pxEnd. */
|
||||||
xFreeBytesRemaining -= heapSTRUCT_SIZE;
|
xFreeBytesRemaining -= heapSTRUCT_SIZE;
|
||||||
|
|
||||||
|
/* Work out the position of the top bit in a size_t variable. */
|
||||||
|
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
|
@ -123,14 +123,19 @@
|
||||||
number of bits implemented by the interrupt controller. */
|
number of bits implemented by the interrupt controller. */
|
||||||
#if configUNIQUE_INTERRUPT_PRIORITIES == 16
|
#if configUNIQUE_INTERRUPT_PRIORITIES == 16
|
||||||
#define portPRIORITY_SHIFT 4
|
#define portPRIORITY_SHIFT 4
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 3
|
||||||
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32
|
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32
|
||||||
#define portPRIORITY_SHIFT 3
|
#define portPRIORITY_SHIFT 3
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 2
|
||||||
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64
|
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64
|
||||||
#define portPRIORITY_SHIFT 2
|
#define portPRIORITY_SHIFT 2
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 1
|
||||||
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128
|
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128
|
||||||
#define portPRIORITY_SHIFT 1
|
#define portPRIORITY_SHIFT 1
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 0
|
||||||
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256
|
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256
|
||||||
#define portPRIORITY_SHIFT 0
|
#define portPRIORITY_SHIFT 0
|
||||||
|
#define portMAX_BINARY_POINT_VALUE 0
|
||||||
#else
|
#else
|
||||||
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
|
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
|
||||||
#endif
|
#endif
|
||||||
|
@ -154,11 +159,19 @@ context. */
|
||||||
#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )
|
#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )
|
||||||
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )
|
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )
|
||||||
#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )
|
#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )
|
||||||
|
#define portICCBPR_BINARY_POINT_OFFSET ( 0x08 )
|
||||||
|
#define portICCRPR_RUNNING_PRIORITY_OFFSET ( 0x14 )
|
||||||
#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
|
#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
|
||||||
#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
|
#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
|
||||||
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
|
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
|
||||||
#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
|
#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
|
||||||
#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )
|
#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )
|
||||||
|
#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile unsigned long * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )
|
||||||
|
#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile unsigned char * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )
|
||||||
|
|
||||||
|
/* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
|
||||||
|
point is zero. */
|
||||||
|
#define portBINARY_POINT_BITS ( ( unsigned char ) 0x03 )
|
||||||
|
|
||||||
/* Constants required to setup the initial task context. */
|
/* Constants required to setup the initial task context. */
|
||||||
#define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
|
#define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
|
||||||
|
@ -200,11 +213,6 @@ the scheduler starts. As it is stored as part of the task context it will
|
||||||
automatically be set to 0 when the first task is started. */
|
automatically be set to 0 when the first task is started. */
|
||||||
volatile unsigned long ulCriticalNesting = 9999UL;
|
volatile unsigned long ulCriticalNesting = 9999UL;
|
||||||
|
|
||||||
/* The value to be written to the interrupt controllers priority mask register
|
|
||||||
to mask interrupts that can use the FreeRTOS API without masking higher priority
|
|
||||||
interrupts. */
|
|
||||||
const unsigned long ulPortAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
|
|
||||||
|
|
||||||
/* Used to pass constants into the ASM code. The address at which variables are
|
/* Used to pass constants into the ASM code. The address at which variables are
|
||||||
placed is the constant value so indirect loads in the asm code are not
|
placed is the constant value so indirect loads in the asm code are not
|
||||||
required. */
|
required. */
|
||||||
|
@ -312,6 +320,13 @@ unsigned long ulAPSR;
|
||||||
configASSERT( ulAPSR != portAPSR_USER_MODE );
|
configASSERT( ulAPSR != portAPSR_USER_MODE );
|
||||||
|
|
||||||
if( ulAPSR != portAPSR_USER_MODE )
|
if( ulAPSR != portAPSR_USER_MODE )
|
||||||
|
{
|
||||||
|
/* Only continue if the binary point value is set to its lowest possible
|
||||||
|
setting. See the comments in vPortValidateInterruptPriority() below for
|
||||||
|
more information. */
|
||||||
|
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
|
||||||
|
|
||||||
|
if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
|
||||||
{
|
{
|
||||||
/* Start the timer that generates the tick ISR. */
|
/* Start the timer that generates the tick ISR. */
|
||||||
configSETUP_TICK_INTERRUPT();
|
configSETUP_TICK_INTERRUPT();
|
||||||
|
@ -319,9 +334,11 @@ unsigned long ulAPSR;
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
vPortRestoreTaskContext();
|
vPortRestoreTaskContext();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Will only get here if xTaskStartScheduler() was called with the CPU in
|
/* Will only get here if xTaskStartScheduler() was called with the CPU in
|
||||||
a non-privileged mode. */
|
a non-privileged mode or the binary point register was not set to its lowest
|
||||||
|
possible value. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
@ -371,7 +388,7 @@ void FreeRTOS_Tick_Handler( void )
|
||||||
handler runs at the lowest priority, so interrupts cannot already be masked,
|
handler runs at the lowest priority, so interrupts cannot already be masked,
|
||||||
so there is no need to save and restore the current mask value. */
|
so there is no need to save and restore the current mask value. */
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask;
|
portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
|
||||||
__asm( "DSB \n"
|
__asm( "DSB \n"
|
||||||
"ISB \n" );
|
"ISB \n" );
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
@ -414,7 +431,7 @@ unsigned long ulPortSetInterruptMask( void )
|
||||||
unsigned long ulReturn;
|
unsigned long ulReturn;
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
if( portICCPMR_PRIORITY_MASK_REGISTER == ulPortAPIPriorityMask )
|
if( portICCPMR_PRIORITY_MASK_REGISTER == ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
|
||||||
{
|
{
|
||||||
/* Interrupts were already masked. */
|
/* Interrupts were already masked. */
|
||||||
ulReturn = pdTRUE;
|
ulReturn = pdTRUE;
|
||||||
|
@ -422,7 +439,7 @@ unsigned long ulReturn;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulReturn = pdFALSE;
|
ulReturn = pdFALSE;
|
||||||
portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask;
|
portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
|
||||||
__asm( "DSB \n"
|
__asm( "DSB \n"
|
||||||
"ISB \n" );
|
"ISB \n" );
|
||||||
}
|
}
|
||||||
|
@ -430,5 +447,47 @@ unsigned long ulReturn;
|
||||||
|
|
||||||
return ulReturn;
|
return ulReturn;
|
||||||
}
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( configASSERT_DEFINED == 1 )
|
||||||
|
|
||||||
|
void vPortValidateInterruptPriority( void )
|
||||||
|
{
|
||||||
|
/* The following assertion will fail if a service routine (ISR) for
|
||||||
|
an interrupt that has been assigned a priority above
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY 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
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY.
|
||||||
|
|
||||||
|
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
|
||||||
|
configMAX_SYSCALL_INTERRUPT_PRIORITY.
|
||||||
|
|
||||||
|
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/RTOS-Cortex-M3-M4.html
|
||||||
|
http://www.freertos.org/FAQHelp.html */
|
||||||
|
configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
|
||||||
|
|
||||||
|
/* Priority grouping: The interrupt controller (GIC) allows the bits
|
||||||
|
that define each interrupt's priority to be split between bits that
|
||||||
|
define the interrupt's pre-emption priority bits and bits that define
|
||||||
|
the interrupt's sub-priority. For simplicity all bits must be defined
|
||||||
|
to be pre-emption priority bits. The following assertion will fail if
|
||||||
|
this is not the case (if some bits represent a sub-priority).
|
||||||
|
|
||||||
|
The priority grouping is configured by the GIC's binary point register
|
||||||
|
(ICCBPR). Writting 0 to ICCBPR will ensure it is set to its lowest
|
||||||
|
possible value (which may be above 0). */
|
||||||
|
configASSERT( portICCBPR_BINARY_POINT_REGISTER <= portMAX_BINARY_POINT_VALUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configASSERT_DEFINED */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,13 @@ void vPortTaskUsesFPU( void );
|
||||||
|
|
||||||
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
|
||||||
|
|
||||||
|
#ifdef configASSERT
|
||||||
|
void vPortValidateInterruptPriority( void );
|
||||||
|
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
|
||||||
|
#else
|
||||||
|
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID()
|
||||||
|
#endif
|
||||||
|
|
||||||
#define portNOP() __nop()
|
#define portNOP() __nop()
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
Loading…
Reference in a new issue