|
94 | 94 | #define portSCB_MEM_FAULT_ENABLE_BIT ( 1UL << 16UL )
|
95 | 95 | /*-----------------------------------------------------------*/
|
96 | 96 |
|
| 97 | +/** |
| 98 | + * @brief Constants required to check the validity of an interrupt priority. |
| 99 | + */ |
| 100 | +#define portNVIC_SHPR2_REG ( *( ( volatile uint32_t * ) 0xE000ED1C ) ) |
| 101 | +#define portFIRST_USER_INTERRUPT_NUMBER ( 16 ) |
| 102 | +#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 ) |
| 103 | +#define portAIRCR_REG ( *( ( volatile uint32_t * ) 0xE000ED0C ) ) |
| 104 | +#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 ) |
| 105 | +#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 ) |
| 106 | +#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL ) |
| 107 | +#define portPRIGROUP_SHIFT ( 8UL ) |
| 108 | +/*-----------------------------------------------------------*/ |
| 109 | + |
97 | 110 | /**
|
98 | 111 | * @brief Constants required to manipulate the FPU.
|
99 | 112 | */
|
@@ -369,6 +382,19 @@ PRIVILEGED_DATA static volatile uint32_t ulCriticalNesting = 0xaaaaaaaaUL;
|
369 | 382 | PRIVILEGED_DATA portDONT_DISCARD volatile SecureContextHandle_t xSecureContext = portNO_SECURE_CONTEXT;
|
370 | 383 | #endif /* configENABLE_TRUSTZONE */
|
371 | 384 |
|
| 385 | +/** |
| 386 | + * @brief Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure |
| 387 | + * FreeRTOS API functions are not called from interrupts that have been assigned |
| 388 | + * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. |
| 389 | + */ |
| 390 | +#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_BASEPRI == 1 ) ) |
| 391 | + |
| 392 | + static uint8_t ucMaxSysCallPriority = 0; |
| 393 | + static uint32_t ulMaxPRIGROUPValue = 0; |
| 394 | + static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * ) portNVIC_IP_REGISTERS_OFFSET_16; |
| 395 | + |
| 396 | +#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_BASEPRI == 1 ) ) */ |
| 397 | + |
372 | 398 | #if ( configUSE_TICKLESS_IDLE == 1 )
|
373 | 399 |
|
374 | 400 | /**
|
@@ -944,6 +970,7 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
944 | 970 | }
|
945 | 971 | }
|
946 | 972 | /*-----------------------------------------------------------*/
|
| 973 | + |
947 | 974 | /* *INDENT-OFF* */
|
948 | 975 | #if ( configENABLE_MPU == 1 )
|
949 | 976 | StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
|
@@ -1069,6 +1096,114 @@ void vPortSVCHandler_C( uint32_t * pulCallerStackAddress ) /* PRIVILEGED_FUNCTIO
|
1069 | 1096 |
|
1070 | 1097 | BaseType_t xPortStartScheduler( void ) /* PRIVILEGED_FUNCTION */
|
1071 | 1098 | {
|
| 1099 | + #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_BASEPRI == 1 ) ) |
| 1100 | + { |
| 1101 | + volatile uint32_t ulOriginalPriority; |
| 1102 | + volatile uint32_t ulImplementedPrioBits = 0; |
| 1103 | + volatile uint8_t ucMaxPriorityValue; |
| 1104 | + |
| 1105 | + /* Determine the maximum priority from which ISR safe FreeRTOS API |
| 1106 | + * functions can be called. ISR safe functions are those that end in |
| 1107 | + * "FromISR". FreeRTOS maintains separate thread and ISR API functions to |
| 1108 | + * ensure interrupt entry is as fast and simple as possible. |
| 1109 | + * |
| 1110 | + * Save the interrupt priority value that is about to be clobbered. */ |
| 1111 | + ulOriginalPriority = portNVIC_SHPR2_REG; |
| 1112 | + |
| 1113 | + /* Determine the number of priority bits available. First write to all |
| 1114 | + * possible bits. */ |
| 1115 | + portNVIC_SHPR2_REG = 0xFF000000; |
| 1116 | + |
| 1117 | + /* Read the value back to see how many bits stuck. */ |
| 1118 | + ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 ); |
| 1119 | + |
| 1120 | + /* Use the same mask on the maximum system call priority. */ |
| 1121 | + ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; |
| 1122 | + |
| 1123 | + /* Check that the maximum system call priority is nonzero after |
| 1124 | + * accounting for the number of priority bits supported by the |
| 1125 | + * hardware. A priority of 0 is invalid because setting the BASEPRI |
| 1126 | + * register to 0 unmasks all interrupts, and interrupts with priority 0 |
| 1127 | + * cannot be masked using BASEPRI. |
| 1128 | + * See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ |
| 1129 | + configASSERT( ucMaxSysCallPriority ); |
| 1130 | + |
| 1131 | + /* Calculate the maximum acceptable priority group value for the number |
| 1132 | + * of bits read back. */ |
| 1133 | + |
| 1134 | + while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) |
| 1135 | + { |
| 1136 | + ulImplementedPrioBits++; |
| 1137 | + ucMaxPriorityValue <<= ( uint8_t ) 0x01; |
| 1138 | + } |
| 1139 | + |
| 1140 | + if( ulImplementedPrioBits == 8 ) |
| 1141 | + { |
| 1142 | + /* When the hardware implements 8 priority bits, there is no way for |
| 1143 | + * the software to configure PRIGROUP to not have sub-priorities. As |
| 1144 | + * a result, the least significant bit is always used for sub-priority |
| 1145 | + * and there are 128 preemption priorities and 2 sub-priorities. |
| 1146 | + * |
| 1147 | + * This may cause some confusion in some cases - for example, if |
| 1148 | + * configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4 |
| 1149 | + * priority interrupts will be masked in Critical Sections as those |
| 1150 | + * are at the same preemption priority. This may appear confusing as |
| 1151 | + * 4 is higher (numerically lower) priority than |
| 1152 | + * configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not |
| 1153 | + * have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY |
| 1154 | + * to 4, this confusion does not happen and the behaviour remains the same. |
| 1155 | + * |
| 1156 | + * The following assert ensures that the sub-priority bit in the |
| 1157 | + * configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned |
| 1158 | + * confusion. */ |
| 1159 | + configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U ); |
| 1160 | + ulMaxPRIGROUPValue = 0; |
| 1161 | + } |
| 1162 | + else |
| 1163 | + { |
| 1164 | + ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits; |
| 1165 | + } |
| 1166 | + |
| 1167 | + /* The interrupt priority bits are not modelled in QEMU and the assert that |
| 1168 | + * checks the number of implemented bits and __NVIC_PRIO_BITS will always fail. |
| 1169 | + * Therefore, this assert is not adding any value for QEMU targets. The config |
| 1170 | + * option `configDISABLE_INTERRUPT_PRIO_BITS_CHECK` should be defined in the |
| 1171 | + * `FreeRTOSConfig.h` for QEMU targets. */ |
| 1172 | + #ifndef configDISABLE_INTERRUPT_PRIO_BITS_CHECK |
| 1173 | + { |
| 1174 | + #ifdef __NVIC_PRIO_BITS |
| 1175 | + { |
| 1176 | + /* |
| 1177 | + * Check that the number of implemented priority bits queried from |
| 1178 | + * hardware is equal to the CMSIS __NVIC_PRIO_BITS configuration macro. |
| 1179 | + */ |
| 1180 | + configASSERT( ulImplementedPrioBits == __NVIC_PRIO_BITS ); |
| 1181 | + } |
| 1182 | + #endif /* __NVIC_PRIO_BITS */ |
| 1183 | + |
| 1184 | + #ifdef configPRIO_BITS |
| 1185 | + { |
| 1186 | + /* |
| 1187 | + * Check that the number of implemented priority bits queried from |
| 1188 | + * hardware is equal to the FreeRTOS configPRIO_BITS configuration macro. |
| 1189 | + */ |
| 1190 | + configASSERT( ulImplementedPrioBits == configPRIO_BITS ); |
| 1191 | + } |
| 1192 | + #endif /* configPRIO_BITS */ |
| 1193 | + } |
| 1194 | + #endif /* #ifndef configDISABLE_INTERRUPT_PRIO_BITS_CHECK */ |
| 1195 | + |
| 1196 | + /* Shift the priority group value back to its position within the AIRCR |
| 1197 | + * register. */ |
| 1198 | + ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; |
| 1199 | + ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; |
| 1200 | + |
| 1201 | + /* Restore the clobbered interrupt priority register to its original |
| 1202 | + * value. */ |
| 1203 | + portNVIC_SHPR2_REG = ulOriginalPriority; |
| 1204 | + } |
| 1205 | + #endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_BASEPRI == 1 ) ) */ |
| 1206 | + |
1072 | 1207 | /* Make PendSV, CallSV and SysTick the same priority as the kernel. */
|
1073 | 1208 | portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
|
1074 | 1209 | portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
|
@@ -1259,3 +1394,64 @@ BaseType_t xPortIsInsideInterrupt( void )
|
1259 | 1394 | return xReturn;
|
1260 | 1395 | }
|
1261 | 1396 | /*-----------------------------------------------------------*/
|
| 1397 | + |
| 1398 | +#if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_BASEPRI == 1 ) ) |
| 1399 | + |
| 1400 | + void vPortValidateInterruptPriority( void ) |
| 1401 | + { |
| 1402 | + uint32_t ulCurrentInterrupt; |
| 1403 | + uint8_t ucCurrentPriority; |
| 1404 | + |
| 1405 | + /* Obtain the number of the currently executing interrupt. */ |
| 1406 | + __asm volatile ( "mrs %0, ipsr" : "=r" ( ulCurrentInterrupt )::"memory" ); |
| 1407 | + |
| 1408 | + /* Is the interrupt number a user defined interrupt? */ |
| 1409 | + if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) |
| 1410 | + { |
| 1411 | + /* Look up the interrupt's priority. */ |
| 1412 | + ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; |
| 1413 | + |
| 1414 | + /* The following assertion will fail if a service routine (ISR) for |
| 1415 | + * an interrupt that has been assigned a priority above |
| 1416 | + * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API |
| 1417 | + * function. ISR safe FreeRTOS API functions must *only* be called |
| 1418 | + * from interrupts that have been assigned a priority at or below |
| 1419 | + * configMAX_SYSCALL_INTERRUPT_PRIORITY. |
| 1420 | + * |
| 1421 | + * Numerically low interrupt priority numbers represent logically high |
| 1422 | + * interrupt priorities, therefore the priority of the interrupt must |
| 1423 | + * be set to a value equal to or numerically *higher* than |
| 1424 | + * configMAX_SYSCALL_INTERRUPT_PRIORITY. |
| 1425 | + * |
| 1426 | + * Interrupts that use the FreeRTOS API must not be left at their |
| 1427 | + * default priority of zero as that is the highest possible priority, |
| 1428 | + * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, |
| 1429 | + * and therefore also guaranteed to be invalid. |
| 1430 | + * |
| 1431 | + * FreeRTOS maintains separate thread and ISR API functions to ensure |
| 1432 | + * interrupt entry is as fast and simple as possible. |
| 1433 | + * |
| 1434 | + * The following links provide detailed information: |
| 1435 | + * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html |
| 1436 | + * https://www.FreeRTOS.org/FAQHelp.html */ |
| 1437 | + configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); |
| 1438 | + } |
| 1439 | + |
| 1440 | + /* Priority grouping: The interrupt controller (NVIC) allows the bits |
| 1441 | + * that define each interrupt's priority to be split between bits that |
| 1442 | + * define the interrupt's pre-emption priority bits and bits that define |
| 1443 | + * the interrupt's sub-priority. For simplicity all bits must be defined |
| 1444 | + * to be pre-emption priority bits. The following assertion will fail if |
| 1445 | + * this is not the case (if some bits represent a sub-priority). |
| 1446 | + * |
| 1447 | + * If the application only uses CMSIS libraries for interrupt |
| 1448 | + * configuration then the correct setting can be achieved on all Cortex-M |
| 1449 | + * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the |
| 1450 | + * scheduler. Note however that some vendor specific peripheral libraries |
| 1451 | + * assume a non-zero priority group setting, in which cases using a value |
| 1452 | + * of zero will result in unpredictable behaviour. */ |
| 1453 | + configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); |
| 1454 | + } |
| 1455 | + |
| 1456 | +#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_BASEPRI == 1 ) ) */ |
| 1457 | +/*-----------------------------------------------------------*/ |
0 commit comments