-/*\r
- * FreeRTOS Kernel V10.2.1\r
- * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://www.FreeRTOS.org\r
- * http://aws.amazon.com/freertos\r
- *\r
- * 1 tab == 4 spaces!\r
- */\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-\r
-/** ARMv7 MPU Details:\r
- *\r
- * - ARMv7 MPU requires that the size of a MPU region is a power of 2.\r
- * - Smallest supported region size is 32 bytes.\r
- * - Start address of a region must be aligned to an integer multiple of the\r
- * region size. For example, if the region size is 4 KB(0x1000), the starting\r
- * address must be N x 0x1000, where N is an integer.\r
- */\r
-\r
-/**\r
- * @brief Size of the shared memory region.\r
- */\r
-#define SHARED_MEMORY_SIZE 32\r
-\r
-/**\r
- * @brief Memory region shared between two tasks.\r
- */\r
-static uint8_t ucSharedMemory[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( SHARED_MEMORY_SIZE ) ) );\r
-\r
-/**\r
- * @brief Memory region used to track Memory Fault intentionally caused by the\r
- * RO Access task.\r
- *\r
- * RO Access task sets ucROTaskFaultTracker[ 0 ] to 1 before accessing illegal\r
- * memory. Illegal memory access causes Memory Fault and the fault handler\r
- * checks ucROTaskFaultTracker[ 0 ] to see if this is an expected fault. We\r
- * recover gracefully from an expected fault by jumping to the next instruction.\r
- *\r
- * @note We are declaring a region of 32 bytes even though we need only one.\r
- * The reason is that the smallest supported MPU region size is 32 bytes.\r
- */\r
-static volatile uint8_t ucROTaskFaultTracker[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( SHARED_MEMORY_SIZE ) ) ) = { 0 };\r
-/*-----------------------------------------------------------*/\r
-\r
-/**\r
- * @brief Implements the task which has Read Only access to the memory region\r
- * ucSharedMemory.\r
- *\r
- * @param pvParameters[in] Parameters as passed during task creation.\r
- */\r
-static void prvROAccessTask( void * pvParameters );\r
-\r
-/**\r
- * @brief Implements the task which has Read Write access to the memory region\r
- * ucSharedMemory.\r
- *\r
- * @param pvParameters[in] Parameters as passed during task creation.\r
- */\r
-static void prvRWAccessTask( void * pvParameters );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvROAccessTask( void * pvParameters )\r
-{\r
-uint8_t ucVal;\r
-\r
- /* Unused parameters. */\r
- ( void ) pvParameters;\r
-\r
- for( ; ; )\r
- {\r
- /* This task has RO access to ucSharedMemory and therefore it can read\r
- * it but cannot modify it. */\r
- ucVal = ucSharedMemory[ 0 ];\r
-\r
- /* Silent compiler warnings about unused variables. */\r
- ( void ) ucVal;\r
-\r
- /* Since this task has Read Only access to the ucSharedMemory region,\r
- * writing to it results in Memory Fault. Set ucROTaskFaultTracker[ 0 ]\r
- * to 1 to tell the Memory Fault Handler that this is an expected fault.\r
- * The handler will recover from this fault gracefully by jumping to the\r
- * next instruction. */\r
- ucROTaskFaultTracker[ 0 ] = 1;\r
-\r
- /* Illegal access to generate Memory Fault. */\r
- ucSharedMemory[ 0 ] = 0;\r
-\r
- /* Ensure that the above line did generate MemFault and the fault\r
- * handler did clear the ucROTaskFaultTracker[ 0 ]. */\r
- configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );\r
-\r
- #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )\r
- {\r
- /* Generate an SVC to raise the privilege. Since privilege\r
- * escalation is only allowed from kernel code, this request must\r
- * get rejected and the task must remain unprivileged. As a result,\r
- * trying to write to ucSharedMemory will still result in Memory\r
- * Fault. */\r
- portRAISE_PRIVILEGE();\r
-\r
- /* Set ucROTaskFaultTracker[ 0 ] to 1 to tell the Memory Fault\r
- * Handler that this is an expected fault. The handler will then be\r
- * able to recover from this fault gracefully by jumping to the\r
- * next instruction.*/\r
- ucROTaskFaultTracker[ 0 ] = 1;\r
-\r
- /* The following must still result in Memory Fault since the task\r
- * is still running unprivileged. */\r
- ucSharedMemory[ 0 ] = 0;\r
-\r
- /* Ensure that the above line did generate MemFault and the fault\r
- * handler did clear the ucROTaskFaultTracker[ 0 ]. */\r
- configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );\r
- }\r
- #else\r
- {\r
- /* Generate an SVC to raise the privilege. Since\r
- * configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not enabled, the\r
- * task will be able to escalate privilege. */\r
- portRAISE_PRIVILEGE();\r
-\r
- /* At this point, the task is running privileged. The following\r
- * access must not result in Memory Fault. If something goes\r
- * wrong and we do get a fault, the execution will stop in fault\r
- * handler as ucROTaskFaultTracker[ 0 ] is not set (i.e.\r
- * un-expected fault). */\r
- ucSharedMemory[ 0 ] = 0;\r
-\r
- /* Lower down the privilege. */\r
- portSWITCH_TO_USER_MODE();\r
-\r
- /* Now the task is running unprivileged and therefore an attempt to\r
- * write to ucSharedMemory will result in a Memory Fault. Set\r
- * ucROTaskFaultTracker[ 0 ] to 1 to tell the Memory Fault Handler\r
- * that this is an expected fault. The handler will then be able to\r
- * recover from this fault gracefully by jumping to the next\r
- * instruction.*/\r
- ucROTaskFaultTracker[ 0 ] = 1;\r
-\r
- /* The following must result in Memory Fault since the task is now\r
- * running unprivileged. */\r
- ucSharedMemory[ 0 ] = 0;\r
-\r
- /* Ensure that the above line did generate MemFault and the fault\r
- * handler did clear the ucROTaskFaultTracker[ 0 ]. */\r
- configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );\r
- }\r
- #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */\r
-\r
- /* Wait for a second. */\r
- vTaskDelay( pdMS_TO_TICKS( 1000 ) );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvRWAccessTask( void * pvParameters )\r
-{\r
- /* Unused parameters. */\r
- ( void ) pvParameters;\r
-\r
- for( ; ; )\r
- {\r
- /* This task has RW access to ucSharedMemory and therefore can write to\r
- * it. */\r
- ucSharedMemory[ 0 ] = 0;\r
-\r
- /* Wait for a second. */\r
- vTaskDelay( pdMS_TO_TICKS( 1000 ) );\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vStartMPUDemo( void )\r
-{\r
-/**\r
- * Since stack of a task is protected using MPU, it must satisfy MPU\r
- * requirements as mentioned at the top of this file.\r
- */\r
-static StackType_t xROAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( configMINIMAL_STACK_SIZE * sizeof( StackType_t ) ) ) );\r
-static StackType_t xRWAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( configMINIMAL_STACK_SIZE * sizeof( StackType_t ) ) ) );\r
-TaskParameters_t xROAccessTaskParameters =\r
-{\r
- .pvTaskCode = prvROAccessTask,\r
- .pcName = "ROAccess",\r
- .usStackDepth = configMINIMAL_STACK_SIZE,\r
- .pvParameters = NULL,\r
- .uxPriority = tskIDLE_PRIORITY,\r
- .puxStackBuffer = xROAccessTaskStack,\r
- .xRegions = {\r
- { ucSharedMemory, SHARED_MEMORY_SIZE, portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY | portMPU_REGION_EXECUTE_NEVER },\r
- { ( void * ) ucROTaskFaultTracker, SHARED_MEMORY_SIZE, portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER },\r
- { 0, 0, 0 },\r
- }\r
-};\r
-TaskParameters_t xRWAccessTaskParameters =\r
-{\r
- .pvTaskCode = prvRWAccessTask,\r
- .pcName = "RWAccess",\r
- .usStackDepth = configMINIMAL_STACK_SIZE,\r
- .pvParameters = NULL,\r
- .uxPriority = tskIDLE_PRIORITY,\r
- .puxStackBuffer = xRWAccessTaskStack,\r
- .xRegions = {\r
- { ucSharedMemory, SHARED_MEMORY_SIZE, portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER},\r
- { 0, 0, 0 },\r
- { 0, 0, 0 },\r
- }\r
-};\r
-\r
- /* Create an unprivileged task with RO access to ucSharedMemory. */\r
- xTaskCreateRestricted( &( xROAccessTaskParameters ), NULL );\r
-\r
- /* Create an unprivileged task with RW access to ucSharedMemory. */\r
- xTaskCreateRestricted( &( xRWAccessTaskParameters ), NULL );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-portDONT_DISCARD void vHandleMemoryFault( uint32_t * pulFaultStackAddress )\r
-{\r
-uint32_t ulPC;\r
-uint16_t usOffendingInstruction;\r
-\r
- /* Is this an expected fault? */\r
- if( ucROTaskFaultTracker[ 0 ] == 1 )\r
- {\r
- /* Read program counter. */\r
- ulPC = pulFaultStackAddress[ 6 ];\r
-\r
- /* Read the offending instruction. */\r
- usOffendingInstruction = *( uint16_t * )ulPC;\r
-\r
- /* From ARM docs:\r
- * If the value of bits[15:11] of the halfword being decoded is one of\r
- * the following, the halfword is the first halfword of a 32-bit\r
- * instruction:\r
- * - 0b11101.\r
- * - 0b11110.\r
- * - 0b11111.\r
- * Otherwise, the halfword is a 16-bit instruction.\r
- */\r
-\r
- /* Extract bits[15:11] of the offending instruction. */\r
- usOffendingInstruction = usOffendingInstruction & 0xF800;\r
- usOffendingInstruction = ( usOffendingInstruction >> 11 );\r
-\r
- /* Determine if the offending instruction is a 32-bit instruction or\r
- * a 16-bit instruction. */\r
- if( usOffendingInstruction == 0x001F ||\r
- usOffendingInstruction == 0x001E ||\r
- usOffendingInstruction == 0x001D )\r
- {\r
- /* Since the offending instruction is a 32-bit instruction,\r
- * increment the program counter by 4 to move to the next\r
- * instruction. */\r
- ulPC += 4;\r
- }\r
- else\r
- {\r
- /* Since the offending instruction is a 16-bit instruction,\r
- * increment the program counter by 2 to move to the next\r
- * instruction. */\r
- ulPC += 2;\r
- }\r
-\r
- /* Save the new program counter on the stack. */\r
- pulFaultStackAddress[ 6 ] = ulPC;\r
-\r
- /* Mark the fault as handled. */\r
- ucROTaskFaultTracker[ 0 ] = 0;\r
- }\r
- else\r
- {\r
- /* This is an unexpected fault - loop forever. */\r
- for( ; ; )\r
- {\r
- }\r
- }\r
-}\r
-/*-----------------------------------------------------------*/\r