diff --git a/portable/ARMv8M/non_secure/port.c b/portable/ARMv8M/non_secure/port.c index 9c3794c6b..c0cb54008 100644 --- a/portable/ARMv8M/non_secure/port.c +++ b/portable/ARMv8M/non_secure/port.c @@ -2194,7 +2194,7 @@ void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */ { #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) { - volatile uint32_t ulImplementedPrioBits = 0; + volatile uint32_t ulNumPreemptPrioBits = 0; volatile uint8_t ucMaxPriorityValue; /* Determine the maximum priority from which ISR safe FreeRTOS API @@ -2202,12 +2202,30 @@ void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */ * "FromISR". FreeRTOS maintains separate thread and ISR API functions to * ensure interrupt entry is as fast and simple as possible. * - * First, determine the number of priority bits available. Write to all - * possible bits in the priority setting for SVCall. */ - portNVIC_SHPR2_REG = 0xFF000000; + * First, determine the number of preemption priority bits available. + * Write to all 7 possible bits in the priority setting for SVCall. If + * the hardware implements 8 bits, the least-significant bit is used for + * sub-priority, not preemption priority, so we don't need check that + * bit. */ + portNVIC_SHPR2_REG = 0xFE000000; /* Read the value back to see how many bits stuck. */ - ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFF000000 ) >> 24 ); + ucMaxPriorityValue = ( uint8_t ) ( ( portNVIC_SHPR2_REG & 0xFE000000 ) >> 24 ); + + #if ( configENABLE_TRUSTZONE == 1 ) + { + /* In TrustZone applications, the maximum value must not use the + * least-significant bit of preemption priority. That bit must be + * zero because the hardware ignores it during de-prioritization of + * non-secure exceptions. */ + ucMaxPriorityValue <<= ( uint8_t ) 0x01; + + /* Initialize the counter of preemption-priority bits to 1 instead + * of 0. The work of counting the implemented preemption-priority + * bits continues further below. */ + ulNumPreemptPrioBits = 1; + } + #endif /* #if ( configENABLE_TRUSTZONE == 1 ) */ /* Use the same mask on the maximum system call priority. */ ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; @@ -2220,44 +2238,42 @@ void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */ * See https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ configASSERT( ucMaxSysCallPriority ); - /* Check that the bits not implemented in hardware are zero in - * configMAX_SYSCALL_INTERRUPT_PRIORITY. */ + /* Check that the bits not implemented in hardware as preemption- + * priority bits are zero in configMAX_SYSCALL_INTERRUPT_PRIORITY. + * + * In TrustZone applications, this check also ensures that the least- + * significant preemption-priority bit is zero in + * configMAX_SYSCALL_INTERRUPT_PRIORITY. The hardware ignores that bit + * when de-prioritizing non-secure exceptions, so it must be zero to + * ensure that the maximum system call priority is not higher than the + * application writer expects. + * + * This check also ensures that the sub-priority bit (if present) is + * zero in configMAX_SYSCALL_INTERRUPT_PRIORITY. When the hardware + * implements 8 priority bits, there is no way for the software to + * configure PRIGROUP to not have sub-priorities. As a result, the + * least significant bit is always used for sub-priority, and there are + * 128 preemption priorities and 2 sub-priorities. + * + * This may cause some confusion in some cases - for example, if + * configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4 + * priority interrupts will be masked in Critical Sections as those + * are at the same preemption priority. This may appear confusing as + * 4 is higher (numerically lower) priority than + * configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not + * have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY + * to 4, this confusion does not happen and the behaviour remains the same. */ configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & ( uint8_t ) ( ~( uint32_t ) ucMaxPriorityValue ) ) == 0U ); /* Calculate the maximum acceptable priority group value for the number - * of bits read back. */ + * of preemption-priority bits implemented in the hardware. */ while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) { - ulImplementedPrioBits++; + ulNumPreemptPrioBits++; ucMaxPriorityValue <<= ( uint8_t ) 0x01; } - if( ulImplementedPrioBits == 8 ) - { - /* When the hardware implements 8 priority bits, there is no way for - * the software to configure PRIGROUP to not have sub-priorities. As - * a result, the least significant bit is always used for sub-priority - * and there are 128 preemption priorities and 2 sub-priorities. - * - * This may cause some confusion in some cases - for example, if - * configMAX_SYSCALL_INTERRUPT_PRIORITY is set to 5, both 5 and 4 - * priority interrupts will be masked in Critical Sections as those - * are at the same preemption priority. This may appear confusing as - * 4 is higher (numerically lower) priority than - * configMAX_SYSCALL_INTERRUPT_PRIORITY and therefore, should not - * have been masked. Instead, if we set configMAX_SYSCALL_INTERRUPT_PRIORITY - * to 4, this confusion does not happen and the behaviour remains the same. - * - * The following assert ensures that the sub-priority bit in the - * configMAX_SYSCALL_INTERRUPT_PRIORITY is clear to avoid the above mentioned - * confusion. */ - configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY & 0x1U ) == 0U ); - ulMaxPRIGROUPValue = 0; - } - else - { - ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulImplementedPrioBits; - } + ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS - ulNumPreemptPrioBits; /* Shift the priority group value back to its position within the AIRCR * register. */