348 lines
15 KiB
C
348 lines
15 KiB
C
/*
|
|
* FreeRTOS V202212.00
|
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
* subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* https://www.FreeRTOS.org
|
|
* https://github.com/FreeRTOS
|
|
*
|
|
*/
|
|
|
|
/* FreeRTOS includes. */
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
|
|
/**
|
|
* @brief Size of the shared memory region.
|
|
*/
|
|
#define SHARED_MEMORY_SIZE 32
|
|
|
|
/**
|
|
* @brief Memory region shared between two tasks.
|
|
*/
|
|
static uint8_t ucSharedMemory[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
#if ( configTOTAL_MPU_REGIONS == 16 )
|
|
static uint8_t ucSharedMemory1[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
static uint8_t ucSharedMemory2[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
static uint8_t ucSharedMemory3[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
static uint8_t ucSharedMemory4[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
static uint8_t ucSharedMemory5[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
static uint8_t ucSharedMemory6[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
static uint8_t ucSharedMemory7[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
static uint8_t ucSharedMemory8[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
|
|
|
/**
|
|
* @brief Memory region used to track Memory Fault intentionally caused by the
|
|
* RO Access task.
|
|
*
|
|
* RO Access task sets ucROTaskFaultTracker[ 0 ] to 1 before accessing illegal
|
|
* memory. Illegal memory access causes Memory Fault and the fault handler
|
|
* checks ucROTaskFaultTracker[ 0 ] to see if this is an expected fault. We
|
|
* recover gracefully from an expected fault by jumping to the next instruction.
|
|
*
|
|
* @note We are declaring a region of 32 bytes even though we need only one. The
|
|
* reason is that the size of an MPU region must be a multiple of 32 bytes.
|
|
*/
|
|
static volatile uint8_t ucROTaskFaultTracker[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( 32 ) ) ) = { 0 };
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/**
|
|
* @brief Implements the task which has Read Only access to the memory region
|
|
* ucSharedMemory.
|
|
*
|
|
* @param pvParameters[in] Parameters as passed during task creation.
|
|
*/
|
|
static void prvROAccessTask( void * pvParameters );
|
|
|
|
/**
|
|
* @brief Implements the task which has Read Write access to the memory region
|
|
* ucSharedMemory.
|
|
*
|
|
* @param pvParameters[in] Parameters as passed during task creation.
|
|
*/
|
|
static void prvRWAccessTask( void * pvParameters );
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvROAccessTask( void * pvParameters )
|
|
{
|
|
uint8_t ucVal;
|
|
|
|
/* Unused parameters. */
|
|
( void ) pvParameters;
|
|
|
|
for( ; ; )
|
|
{
|
|
/* This task performs the following sequence for all the shared memory
|
|
* regions:
|
|
*
|
|
* 1. Perfrom a read access to the shared memory. Since this task has
|
|
* RO access to the shared memory, the read operation is successful.
|
|
*
|
|
* 2. Set ucROTaskFaultTracker[ 0 ] to 1 before performing a write to
|
|
* the shared memory. Since this task has Read Only access to the
|
|
* shared memory, the write operation would result in a Memory Fault.
|
|
* Setting ucROTaskFaultTracker[ 0 ] to 1 tells the Memory Fault
|
|
* Handler that this is an expected fault. The handler recovers from
|
|
* the expected fault gracefully by jumping to the next instruction.
|
|
*
|
|
* 3. Perfrom a write to the shared memory resulting in a memory fault.
|
|
*
|
|
* 4. Ensure that the write access did generate MemFault and the fault
|
|
* handler did clear the ucROTaskFaultTracker[ 0 ].
|
|
*/
|
|
/* Perform the above mentioned sequence on ucSharedMemory. */
|
|
ucVal = ucSharedMemory[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
|
|
#if ( configTOTAL_MPU_REGIONS == 16 )
|
|
{
|
|
/* Perform the above mentioned sequence on ucSharedMemory1. */
|
|
ucVal = ucSharedMemory1[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory1[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
|
|
/* Perform the above mentioned sequence on ucSharedMemory2. */
|
|
ucVal = ucSharedMemory2[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory2[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
|
|
/* Perform the above mentioned sequence on ucSharedMemory3. */
|
|
ucVal = ucSharedMemory3[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory3[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
|
|
/* Perform the above mentioned sequence on ucSharedMemory4. */
|
|
ucVal = ucSharedMemory4[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory4[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
|
|
/* Perform the above mentioned sequence on ucSharedMemory5. */
|
|
ucVal = ucSharedMemory5[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory5[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
|
|
/* Perform the above mentioned sequence on ucSharedMemory6. */
|
|
ucVal = ucSharedMemory6[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory6[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
|
|
/* Perform the above mentioned sequence on ucSharedMemory7. */
|
|
ucVal = ucSharedMemory7[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory7[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
|
|
/* Perform the above mentioned sequence on ucSharedMemory8. */
|
|
ucVal = ucSharedMemory8[ 0 ];
|
|
/* Silent compiler warnings about unused variables. */
|
|
( void ) ucVal;
|
|
ucROTaskFaultTracker[ 0 ] = 1;
|
|
ucSharedMemory8[ 0 ] = 0;
|
|
configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );
|
|
}
|
|
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
|
|
|
/* Wait for a second. */
|
|
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
static void prvRWAccessTask( void * pvParameters )
|
|
{
|
|
/* Unused parameters. */
|
|
( void ) pvParameters;
|
|
|
|
for( ; ; )
|
|
{
|
|
/* This task has RW access to ucSharedMemory and therefore can write to
|
|
* it. */
|
|
ucSharedMemory[ 0 ] = 0;
|
|
|
|
#if ( configTOTAL_MPU_REGIONS == 16 )
|
|
{
|
|
ucSharedMemory1[ 0 ] = 0;
|
|
ucSharedMemory2[ 0 ] = 0;
|
|
ucSharedMemory3[ 0 ] = 0;
|
|
ucSharedMemory4[ 0 ] = 0;
|
|
ucSharedMemory5[ 0 ] = 0;
|
|
ucSharedMemory6[ 0 ] = 0;
|
|
ucSharedMemory7[ 0 ] = 0;
|
|
ucSharedMemory8[ 0 ] = 0;
|
|
}
|
|
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
|
|
|
/* Wait for a second. */
|
|
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
void vStartMPUDemo( void )
|
|
{
|
|
static StackType_t xROAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
static StackType_t xRWAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( 32 ) ) );
|
|
TaskParameters_t xROAccessTaskParameters =
|
|
{
|
|
.pvTaskCode = prvROAccessTask,
|
|
.pcName = "ROAccess",
|
|
.usStackDepth = configMINIMAL_STACK_SIZE,
|
|
.pvParameters = NULL,
|
|
.uxPriority = tskIDLE_PRIORITY,
|
|
.puxStackBuffer = xROAccessTaskStack,
|
|
.xRegions =
|
|
{
|
|
{ ( void * ) ucSharedMemory, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
#if ( configTOTAL_MPU_REGIONS == 16 )
|
|
{ ( void * ) ucSharedMemory1, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory2, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory3, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory4, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory5, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory6, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory7, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory8, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
|
|
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
|
{ ( void * ) ucROTaskFaultTracker, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ 0, 0, 0 },
|
|
}
|
|
};
|
|
TaskParameters_t xRWAccessTaskParameters =
|
|
{
|
|
.pvTaskCode = prvRWAccessTask,
|
|
.pcName = "RWAccess",
|
|
.usStackDepth = configMINIMAL_STACK_SIZE,
|
|
.pvParameters = NULL,
|
|
.uxPriority = tskIDLE_PRIORITY,
|
|
.puxStackBuffer = xRWAccessTaskStack,
|
|
.xRegions =
|
|
{
|
|
{ ( void * ) ucSharedMemory, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
#if ( configTOTAL_MPU_REGIONS == 16 )
|
|
{ ( void * ) ucSharedMemory1, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory2, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory3, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory4, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory5, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory6, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory7, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
{ ( void * ) ucSharedMemory8, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
|
|
#endif /* configTOTAL_MPU_REGIONS == 16 */
|
|
{ 0, 0, 0 },
|
|
{ 0, 0, 0 },
|
|
}
|
|
};
|
|
|
|
/* Create an unprivileged task with RO access to ucSharedMemory. */
|
|
xTaskCreateRestricted( &( xROAccessTaskParameters ), NULL );
|
|
|
|
/* Create an unprivileged task with RW access to ucSharedMemory. */
|
|
xTaskCreateRestricted( &( xRWAccessTaskParameters ), NULL );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
portDONT_DISCARD void vHandleMemoryFault( uint32_t * pulFaultStackAddress )
|
|
{
|
|
uint32_t ulPC;
|
|
uint16_t usOffendingInstruction;
|
|
|
|
/* Is this an expected fault? */
|
|
if( ucROTaskFaultTracker[ 0 ] == 1 )
|
|
{
|
|
/* Read program counter. */
|
|
ulPC = pulFaultStackAddress[ 6 ];
|
|
|
|
/* Read the offending instruction. */
|
|
usOffendingInstruction = *( uint16_t * ) ulPC;
|
|
|
|
/* From ARM docs:
|
|
* If the value of bits[15:11] of the halfword being decoded is one of
|
|
* the following, the halfword is the first halfword of a 32-bit
|
|
* instruction:
|
|
* - 0b11101.
|
|
* - 0b11110.
|
|
* - 0b11111.
|
|
* Otherwise, the halfword is a 16-bit instruction.
|
|
*/
|
|
|
|
/* Extract bits[15:11] of the offending instruction. */
|
|
usOffendingInstruction = usOffendingInstruction & 0xF800;
|
|
usOffendingInstruction = ( usOffendingInstruction >> 11 );
|
|
|
|
/* Determine if the offending instruction is a 32-bit instruction or
|
|
* a 16-bit instruction. */
|
|
if( ( usOffendingInstruction == 0x001F ) ||
|
|
( usOffendingInstruction == 0x001E ) ||
|
|
( usOffendingInstruction == 0x001D ) )
|
|
{
|
|
/* Since the offending instruction is a 32-bit instruction,
|
|
* increment the program counter by 4 to move to the next
|
|
* instruction. */
|
|
ulPC += 4;
|
|
}
|
|
else
|
|
{
|
|
/* Since the offending instruction is a 16-bit instruction,
|
|
* increment the program counter by 2 to move to the next
|
|
* instruction. */
|
|
ulPC += 2;
|
|
}
|
|
|
|
/* Save the new program counter on the stack. */
|
|
pulFaultStackAddress[ 6 ] = ulPC;
|
|
|
|
/* Mark the fault as handled. */
|
|
ucROTaskFaultTracker[ 0 ] = 0;
|
|
}
|
|
else
|
|
{
|
|
/* This is an unexpected fault - loop forever. */
|
|
for( ; ; )
|
|
{
|
|
}
|
|
}
|
|
}
|
|
/*-----------------------------------------------------------*/
|