From: richardbarry Date: Tue, 9 Jul 2013 12:49:49 +0000 (+0000) Subject: Enhance heap_4.c to prevent blocks accidentally being freed twice, or blocks that... X-Git-Tag: V7.5.0~23 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=faea1b8f970e8670a1c957a7902a00fb5328671c;p=freertos 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. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1967 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- diff --git a/FreeRTOS/Source/portable/IAR/ARM_CA9/port.c b/FreeRTOS/Source/portable/IAR/ARM_CA9/port.c index 1e731a21e..bca0137d1 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CA9/port.c +++ b/FreeRTOS/Source/portable/IAR/ARM_CA9/port.c @@ -143,6 +143,10 @@ context. */ #define portINTERRUPT_ENABLE_BIT ( 0x80UL ) #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. */ #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. */ 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 a floating point context must be saved and restored for the task. */ unsigned long ulPortTaskHasFPUContext = pdFALSE; @@ -193,6 +192,7 @@ unsigned long ulPortYieldRequired = pdFALSE; if the nesting depth is 0. */ unsigned long ulPortInterruptNesting = 0UL; + /*-----------------------------------------------------------*/ /* @@ -282,15 +282,24 @@ unsigned long ulAPSR; if( ulAPSR != portAPSR_USER_MODE ) { - /* Start the timer that generates the tick ISR. */ - configSETUP_TICK_INTERRUPT(); + /* 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 ); - __enable_irq(); - vPortRestoreTaskContext(); + if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE ) + { + /* Start the timer that generates the tick ISR. */ + configSETUP_TICK_INTERRUPT(); + + __enable_irq(); + vPortRestoreTaskContext(); + } } /* 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; } /*-----------------------------------------------------------*/ @@ -340,7 +349,7 @@ void FreeRTOS_Tick_Handler( void ) 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. */ __disable_irq(); - portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask; + portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ); __asm( "DSB \n" "ISB \n" ); __enable_irq(); @@ -383,7 +392,7 @@ unsigned long ulPortSetInterruptMask( void ) unsigned long ulReturn; __disable_irq(); - if( portICCPMR_PRIORITY_MASK_REGISTER == ulPortAPIPriorityMask ) + if( portICCPMR_PRIORITY_MASK_REGISTER == ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ) { /* Interrupts were already masked. */ ulReturn = pdTRUE; @@ -391,7 +400,7 @@ unsigned long ulReturn; else { ulReturn = pdFALSE; - portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask; + portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ); __asm( "DSB \n" "ISB \n" ); } @@ -399,5 +408,45 @@ unsigned long 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 */ diff --git a/FreeRTOS/Source/portable/IAR/ARM_CA9/portmacro.h b/FreeRTOS/Source/portable/IAR/ARM_CA9/portmacro.h index 5ce489c02..2f1f13d55 100644 --- a/FreeRTOS/Source/portable/IAR/ARM_CA9/portmacro.h +++ b/FreeRTOS/Source/portable/IAR/ARM_CA9/portmacro.h @@ -77,145 +77,163 @@ /* IAR includes. */ #ifdef __ICCARM__ + #include -#ifdef __cplusplus -extern "C" { -#endif + #ifdef __cplusplus + extern "C" { + #endif + + /*----------------------------------------------------------- + * Port specific definitions. + * + * The settings in this file configure FreeRTOS correctly for the given hardware + * and compiler. + * + * These settings should not be altered. + *----------------------------------------------------------- + */ + + /* Type definitions. */ + #define portCHAR char + #define portFLOAT float + #define portDOUBLE double + #define portLONG long + #define portSHORT short + #define portSTACK_TYPE unsigned long + #define portBASE_TYPE portLONG + typedef unsigned long portTickType; + #define portMAX_DELAY ( portTickType ) 0xffffffff + + /*-----------------------------------------------------------*/ + + /* Hardware specifics. */ + #define portSTACK_GROWTH ( -1 ) + #define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) + #define portBYTE_ALIGNMENT 8 -/*----------------------------------------------------------- - * Port specific definitions. - * - * The settings in this file configure FreeRTOS correctly for the given hardware - * and compiler. - * - * These settings should not be altered. - *----------------------------------------------------------- - */ - -/* Type definitions. */ -#define portCHAR char -#define portFLOAT float -#define portDOUBLE double -#define portLONG long -#define portSHORT short -#define portSTACK_TYPE unsigned long -#define portBASE_TYPE portLONG -typedef unsigned long portTickType; -#define portMAX_DELAY ( portTickType ) 0xffffffff - -/*-----------------------------------------------------------*/ - -/* Hardware specifics. */ -#define portSTACK_GROWTH ( -1 ) -#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) -#define portBYTE_ALIGNMENT 8 - -/*-----------------------------------------------------------*/ - -/* Task utilities. */ - -/* Called at the end of an ISR that can cause a context switch. */ -#define portEND_SWITCHING_ISR( xSwitchRequired )\ -{ \ -extern unsigned long ulPortYieldRequired; \ - \ - if( xSwitchRequired != pdFALSE ) \ - { \ - ulPortYieldRequired = pdTRUE; \ - } \ -} - -#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) -#define portYIELD() __asm( "SWI 0" ); - - -/*----------------------------------------------------------- - * Critical section control - *----------------------------------------------------------*/ - -extern void vPortEnterCritical( void ); -extern void vPortExitCritical( void ); -extern unsigned long ulPortSetInterruptMask( void ); -extern void vPortClearInterruptMask( unsigned long ulNewMaskValue ); - -/* These macros do not globally disable/enable interrupts. They do mask off -interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */ -#define portENTER_CRITICAL() vPortEnterCritical(); -#define portEXIT_CRITICAL() vPortExitCritical(); -#define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() -#define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 ) -#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() -#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) - -/*-----------------------------------------------------------*/ - -/* Task function macros as described on the FreeRTOS.org WEB site. These are -not required for this port but included in case common demo code that uses these -macros is used. */ -#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) -#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) - -/* Prototype of the FreeRTOS tick handler. This must be installed as the -handler for whichever peripheral is used to generate the RTOS tick. */ -void FreeRTOS_Tick_Handler( void ); - -/* Any task that uses the floating point unit MUST call vPortTaskUsesFPU() -before any floating point instructions are executed. */ -void vPortTaskUsesFPU( void ); -#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU() - -#define portLOWEST_INTERRUPT_PRIORITY ( ( ( unsigned long ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL ) -#define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL ) - -/* Architecture specific optimisations. */ -#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 - - /* Store/clear the ready priorities in a bit map. */ - #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) - #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) + /*-----------------------------------------------------------*/ + + /* Task utilities. */ + + /* Called at the end of an ISR that can cause a context switch. */ + #define portEND_SWITCHING_ISR( xSwitchRequired )\ + { \ + extern unsigned long ulPortYieldRequired; \ + \ + if( xSwitchRequired != pdFALSE ) \ + { \ + ulPortYieldRequired = pdTRUE; \ + } \ + } + + #define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x ) + #define portYIELD() __asm( "SWI 0" ); + + + /*----------------------------------------------------------- + * Critical section control + *----------------------------------------------------------*/ + + extern void vPortEnterCritical( void ); + extern void vPortExitCritical( void ); + extern unsigned long ulPortSetInterruptMask( void ); + extern void vPortClearInterruptMask( unsigned long ulNewMaskValue ); + + /* These macros do not globally disable/enable interrupts. They do mask off + interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */ + #define portENTER_CRITICAL() vPortEnterCritical(); + #define portEXIT_CRITICAL() vPortExitCritical(); + #define portDISABLE_INTERRUPTS() ulPortSetInterruptMask() + #define portENABLE_INTERRUPTS() vPortClearInterruptMask( 0 ) + #define portSET_INTERRUPT_MASK_FROM_ISR() ulPortSetInterruptMask() + #define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x) /*-----------------------------------------------------------*/ - #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( uxReadyPriorities ) ) + /* Task function macros as described on the FreeRTOS.org WEB site. These are + not required for this port but included in case common demo code that uses these + macros is used. */ + #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) + #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) -#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */ + /* Prototype of the FreeRTOS tick handler. This must be installed as the + handler for whichever peripheral is used to generate the RTOS tick. */ + void FreeRTOS_Tick_Handler( void ); -#ifdef __cplusplus -} -#endif + /* Any task that uses the floating point unit MUST call vPortTaskUsesFPU() + before any floating point instructions are executed. */ + void vPortTaskUsesFPU( void ); + #define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU() -#endif /* __ICCARM__ */ + #define portLOWEST_INTERRUPT_PRIORITY ( ( ( unsigned long ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL ) + #define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL ) + + /* Architecture specific optimisations. */ + #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 -#define portNOP() __asm volatile( "NOP" ) + /* Store/clear the ready priorities in a bit map. */ + #define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) ) + #define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) ) + + /*-----------------------------------------------------------*/ + + #define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __CLZ( uxReadyPriorities ) ) + + #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 + } + #endif + +#endif /* __ICCARM__ */ /* The number of bits to shift for an interrupt priority is dependent on the number of bits implemented by the interrupt controller. */ #if configUNIQUE_INTERRUPT_PRIORITIES == 16 #define portPRIORITY_SHIFT 4 + #define portMAX_BINARY_POINT_VALUE 3 #elif configUNIQUE_INTERRUPT_PRIORITIES == 32 #define portPRIORITY_SHIFT 3 + #define portMAX_BINARY_POINT_VALUE 2 #elif configUNIQUE_INTERRUPT_PRIORITIES == 64 #define portPRIORITY_SHIFT 2 + #define portMAX_BINARY_POINT_VALUE 1 #elif configUNIQUE_INTERRUPT_PRIORITIES == 128 #define portPRIORITY_SHIFT 1 + #define portMAX_BINARY_POINT_VALUE 0 #elif configUNIQUE_INTERRUPT_PRIORITIES == 256 #define portPRIORITY_SHIFT 0 + #define portMAX_BINARY_POINT_VALUE 0 #else #error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware #endif /* Interrupt controller access addresses. */ -#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 ) -#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C ) -#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 ) -#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 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 portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) - +#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 ) +#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C ) +#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 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 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 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 */ diff --git a/FreeRTOS/Source/portable/MemMang/heap_4.c b/FreeRTOS/Source/portable/MemMang/heap_4.c index b40229fb1..d0d35a1a4 100644 --- a/FreeRTOS/Source/portable/MemMang/heap_4.c +++ b/FreeRTOS/Source/portable/MemMang/heap_4.c @@ -95,8 +95,11 @@ task.h is included from an application file. */ /* Block sizes must not get too small. */ #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. */ -#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) +#define heapADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) /* Allocate the memory for the heap. */ 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 ); /* 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. */ static xBlockLink xStart, *pxEnd = NULL; /* Keeps track of the number of free bytes remaining, but says nothing about 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,63 +166,77 @@ void *pvReturn = NULL; prvHeapInit(); } - /* The wanted size is increased so it can contain a xBlockLink - structure in addition to the requested amount of bytes. */ - if( xWantedSize > 0 ) + /* 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 ) { - xWantedSize += heapSTRUCT_SIZE; - - /* Ensure that blocks are always aligned to the required number of - bytes. */ - if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) + /* The wanted size is increased so it can contain a xBlockLink + structure in addition to the requested amount of bytes. */ + if( xWantedSize > 0 ) { - /* Byte alignment required. */ - xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); - } - } + xWantedSize += heapSTRUCT_SIZE; - if( ( xWantedSize > 0 ) && ( xWantedSize < xTotalHeapSize ) ) - { - /* Traverse the list from the start (lowest address) 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; + /* Ensure that blocks are always aligned to the required number + of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + } } - /* If the end marker was reached then a block of adequate size was - not found. */ - if( pxBlock != pxEnd ) + if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) ) { - /* Return the memory space - jumping over the xBlockLink structure - at its start. */ - pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); - - /* 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 ) + /* Traverse the list from the start (lowest address) block until + one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) { - /* 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 * ) ( ( ( unsigned char * ) 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. */ - prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; } - xFreeBytesRemaining -= pxBlock->xBlockSize; + /* 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 + xBlockLink structure at its start. */ + pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); + + /* 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 * ) ( ( ( unsigned char * ) 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. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + } + + 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,13 +270,27 @@ xBlockLink *pxLink; /* This casting is to keep the compiler from issuing warnings. */ pxLink = ( void * ) puc; - vTaskSuspendAll(); + /* Check the block is actually allocated. */ + configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ); + configASSERT( pxLink->pxNextFreeBlock == NULL ); + + if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ) { - /* Add this block to the list of free blocks. */ - xFreeBytesRemaining += pxLink->xBlockSize; - prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) ); + if( pxLink->pxNextFreeBlock == NULL ) + { + /* The block is being returned to the heap - it is no longer + allocated. */ + pxLink->xBlockSize &= ~xBlockAllocatedBit; + + vTaskSuspendAll(); + { + /* Add this block to the list of free blocks. */ + xFreeBytesRemaining += pxLink->xBlockSize; + prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) ); + } + xTaskResumeAll(); + } } - xTaskResumeAll(); } } /*-----------------------------------------------------------*/ @@ -302,6 +337,9 @@ unsigned char *pucHeapEnd, *pucAlignedHeap; /* The heap now contains pxEnd. */ 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 ); } /*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CA9/port.c b/FreeRTOS/Source/portable/RVDS/ARM_CA9/port.c index fbcb52759..4737f62ff 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CA9/port.c +++ b/FreeRTOS/Source/portable/RVDS/ARM_CA9/port.c @@ -123,14 +123,19 @@ number of bits implemented by the interrupt controller. */ #if configUNIQUE_INTERRUPT_PRIORITIES == 16 #define portPRIORITY_SHIFT 4 + #define portMAX_BINARY_POINT_VALUE 3 #elif configUNIQUE_INTERRUPT_PRIORITIES == 32 #define portPRIORITY_SHIFT 3 + #define portMAX_BINARY_POINT_VALUE 2 #elif configUNIQUE_INTERRUPT_PRIORITIES == 64 #define portPRIORITY_SHIFT 2 + #define portMAX_BINARY_POINT_VALUE 1 #elif configUNIQUE_INTERRUPT_PRIORITIES == 128 #define portPRIORITY_SHIFT 1 + #define portMAX_BINARY_POINT_VALUE 0 #elif configUNIQUE_INTERRUPT_PRIORITIES == 256 #define portPRIORITY_SHIFT 0 + #define portMAX_BINARY_POINT_VALUE 0 #else #error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware #endif @@ -151,14 +156,22 @@ context. */ #define portNO_FLOATING_POINT_CONTEXT ( ( portSTACK_TYPE ) 0 ) /* Interrupt controller access addresses. */ -#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 ) +#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 ) #define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C ) -#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 ) -#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 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 portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) +#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 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 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 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. */ #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. */ 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 placed is the constant value so indirect loads in the asm code are not required. */ @@ -313,15 +321,24 @@ unsigned long ulAPSR; if( ulAPSR != portAPSR_USER_MODE ) { - /* Start the timer that generates the tick ISR. */ - configSETUP_TICK_INTERRUPT(); - - __enable_irq(); - vPortRestoreTaskContext(); + /* 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. */ + configSETUP_TICK_INTERRUPT(); + + __enable_irq(); + vPortRestoreTaskContext(); + } } /* 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; } /*-----------------------------------------------------------*/ @@ -371,7 +388,7 @@ void FreeRTOS_Tick_Handler( void ) 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. */ __disable_irq(); - portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask; + portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ); __asm( "DSB \n" "ISB \n" ); __enable_irq(); @@ -414,7 +431,7 @@ unsigned long ulPortSetInterruptMask( void ) unsigned long ulReturn; __disable_irq(); - if( portICCPMR_PRIORITY_MASK_REGISTER == ulPortAPIPriorityMask ) + if( portICCPMR_PRIORITY_MASK_REGISTER == ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ) { /* Interrupts were already masked. */ ulReturn = pdTRUE; @@ -422,7 +439,7 @@ unsigned long ulReturn; else { ulReturn = pdFALSE; - portICCPMR_PRIORITY_MASK_REGISTER = ulPortAPIPriorityMask; + portICCPMR_PRIORITY_MASK_REGISTER = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ); __asm( "DSB \n" "ISB \n" ); } @@ -430,5 +447,47 @@ unsigned long 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 */ + + diff --git a/FreeRTOS/Source/portable/RVDS/ARM_CA9/portmacro.h b/FreeRTOS/Source/portable/RVDS/ARM_CA9/portmacro.h index 8c177cd07..39bd25fdf 100644 --- a/FreeRTOS/Source/portable/RVDS/ARM_CA9/portmacro.h +++ b/FreeRTOS/Source/portable/RVDS/ARM_CA9/portmacro.h @@ -182,6 +182,13 @@ void vPortTaskUsesFPU( void ); #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() #ifdef __cplusplus