Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 55 additions & 38 deletions portable/ARMv8M/non_secure/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ typedef void ( * portISR_t )( void );
#define portMIN_INTERRUPT_PRIORITY ( 255UL )
#define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL )
#define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL )
#define portNVIC_SVC_PRI ( ( ( uint32_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY - 1UL ) << 24UL )
/*-----------------------------------------------------------*/

/**
Expand Down Expand Up @@ -2194,20 +2195,38 @@ 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
* functions can be called. ISR safe functions are those that end in
* "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;
Expand All @@ -2220,44 +2239,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. */
Expand All @@ -2266,11 +2283,11 @@ void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
}
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */

/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
* the highest priority. */
/* Make PendSV and SysTick the lowest priority interrupts, and configure
* SVCall for sufficient preemption priority. */
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
portNVIC_SHPR2_REG = 0;
portNVIC_SHPR2_REG = portNVIC_SVC_PRI;
}
/*-----------------------------------------------------------*/

Expand Down
93 changes: 55 additions & 38 deletions portable/GCC/ARM_CM23/non_secure/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ typedef void ( * portISR_t )( void );
#define portMIN_INTERRUPT_PRIORITY ( 255UL )
#define portNVIC_PENDSV_PRI ( portMIN_INTERRUPT_PRIORITY << 16UL )
#define portNVIC_SYSTICK_PRI ( portMIN_INTERRUPT_PRIORITY << 24UL )
#define portNVIC_SVC_PRI ( ( ( uint32_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY - 1UL ) << 24UL )
/*-----------------------------------------------------------*/

/**
Expand Down Expand Up @@ -2194,20 +2195,38 @@ 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
* functions can be called. ISR safe functions are those that end in
* "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;
Expand All @@ -2220,44 +2239,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. */
Expand All @@ -2266,11 +2283,11 @@ void vPortConfigureInterruptPriorities( void ) /* PRIVILEGED_FUNCTION */
}
#endif /* #if ( ( configASSERT_DEFINED == 1 ) && ( portHAS_ARMV8M_MAIN_EXTENSION == 1 ) ) */

/* Make PendSV and SysTick the lowest priority interrupts, and make SVCall
* the highest priority. */
/* Make PendSV and SysTick the lowest priority interrupts, and configure
* SVCall for sufficient preemption priority. */
portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
portNVIC_SHPR2_REG = 0;
portNVIC_SHPR2_REG = portNVIC_SVC_PRI;
}
/*-----------------------------------------------------------*/

Expand Down
Loading