]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/CORTEX_MPU_STM32L4_Discovery_GCC_IAR_Keil/Demo/mpu_demo.c
Rename STM32Cube to GCC for STM32L4 Discovery projects as GCC is
[freertos] / FreeRTOS / Demo / CORTEX_MPU_STM32L4_Discovery_GCC_IAR_Keil / Demo / mpu_demo.c
diff --git a/FreeRTOS/Demo/CORTEX_MPU_STM32L4_Discovery_GCC_IAR_Keil/Demo/mpu_demo.c b/FreeRTOS/Demo/CORTEX_MPU_STM32L4_Discovery_GCC_IAR_Keil/Demo/mpu_demo.c
new file mode 100644 (file)
index 0000000..039439a
--- /dev/null
@@ -0,0 +1,301 @@
+/*\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