]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_MPU_STM32L4_Discovery_Keil_STM32Cube/Demo/mpu_demo.c
Make vSetupTimerInterrupt weak in the RVDS M4 MPU port to give the
[freertos] / FreeRTOS / Demo / CORTEX_MPU_STM32L4_Discovery_Keil_STM32Cube / Demo / mpu_demo.c
1 /*\r
2  * FreeRTOS Kernel V10.2.1\r
3  * Copyright (C) 2019 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://www.FreeRTOS.org\r
23  * http://aws.amazon.com/freertos\r
24  *\r
25  * 1 tab == 4 spaces!\r
26  */\r
27 \r
28 /* FreeRTOS includes. */\r
29 #include "FreeRTOS.h"\r
30 #include "task.h"\r
31 \r
32 /** ARMv7 MPU Details:\r
33  *\r
34  * - ARMv7 MPU requires that the size of a MPU region is a power of 2.\r
35  * - Smallest supported region size is 32 bytes.\r
36  * - Start address of a region must be aligned to an integer multiple of the\r
37  *   region size. For example, if the region size is 4 KB(0x1000), the starting\r
38  *   address must be N x 0x1000, where N is an integer.\r
39  */\r
40 \r
41 /**\r
42  * @brief Size of the shared memory region.\r
43  */\r
44 #define SHARED_MEMORY_SIZE 32\r
45 \r
46 /**\r
47  * @brief Memory region shared between two tasks.\r
48  */\r
49 static uint8_t ucSharedMemory[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( SHARED_MEMORY_SIZE ) ) );\r
50 \r
51 /**\r
52  * @brief Memory region used to track Memory Fault intentionally caused by the\r
53  * RO Access task.\r
54  *\r
55  * RO Access task sets ucROTaskFaultTracker[ 0 ] to 1 before accessing illegal\r
56  * memory. Illegal memory access causes Memory Fault and the fault handler\r
57  * checks ucROTaskFaultTracker[ 0 ] to see if this is an expected fault. We\r
58  * recover gracefully from an expected fault by jumping to the next instruction.\r
59  *\r
60  * @note We are declaring a region of 32 bytes even though we need only one.\r
61  * The reason is that the smallest supported MPU region size is 32 bytes.\r
62  */\r
63 static volatile uint8_t ucROTaskFaultTracker[ SHARED_MEMORY_SIZE ] __attribute__( ( aligned( SHARED_MEMORY_SIZE ) ) ) = { 0 };\r
64 /*-----------------------------------------------------------*/\r
65 \r
66 /**\r
67  * @brief Implements the task which has Read Only access to the memory region\r
68  * ucSharedMemory.\r
69  *\r
70  * @param pvParameters[in] Parameters as passed during task creation.\r
71  */\r
72 static void prvROAccessTask( void * pvParameters );\r
73 \r
74 /**\r
75  * @brief Implements the task which has Read Write access to the memory region\r
76  * ucSharedMemory.\r
77  *\r
78  * @param pvParameters[in] Parameters as passed during task creation.\r
79  */\r
80 static void prvRWAccessTask( void * pvParameters );\r
81 \r
82 /*-----------------------------------------------------------*/\r
83 \r
84 static void prvROAccessTask( void * pvParameters )\r
85 {\r
86 uint8_t ucVal;\r
87 \r
88         /* Unused parameters. */\r
89         ( void ) pvParameters;\r
90 \r
91         for( ; ; )\r
92         {\r
93                 /* This task has RO access to ucSharedMemory and therefore it can read\r
94                  * it but cannot modify it. */\r
95                 ucVal = ucSharedMemory[ 0 ];\r
96 \r
97                 /* Silent compiler warnings about unused variables. */\r
98                 ( void ) ucVal;\r
99 \r
100                 /* Since this task has Read Only access to the ucSharedMemory region,\r
101                  * writing to it results in Memory Fault. Set ucROTaskFaultTracker[ 0 ]\r
102                  * to 1 to tell the Memory Fault Handler that this is an expected fault.\r
103                  * The handler will recover from this fault gracefully by jumping to the\r
104                  * next instruction. */\r
105                 ucROTaskFaultTracker[ 0 ] = 1;\r
106 \r
107                 /* Illegal access to generate Memory Fault. */\r
108                 ucSharedMemory[ 0 ] = 0;\r
109 \r
110                 /* Ensure that the above line did generate MemFault and the fault\r
111                  * handler did clear the  ucROTaskFaultTracker[ 0 ]. */\r
112                 configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );\r
113 \r
114                 #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )\r
115                 {\r
116                         /* Generate an SVC to raise the privilege. Since privilege\r
117                          * escalation is only allowed from kernel code, this request must\r
118                          * get rejected and the task must remain unprivileged. As a result,\r
119                          * trying to write to ucSharedMemory will still result in Memory\r
120                          * Fault. */\r
121                         portRAISE_PRIVILEGE();\r
122 \r
123                         /* Set ucROTaskFaultTracker[ 0 ] to 1 to tell the Memory Fault\r
124                          * Handler that this is an expected fault. The handler will then be\r
125                          * able to recover from this fault gracefully by jumping to the\r
126                          * next instruction.*/\r
127                         ucROTaskFaultTracker[ 0 ] = 1;\r
128 \r
129                         /* The following must still result in Memory Fault since the task\r
130                          * is still running unprivileged. */\r
131                         ucSharedMemory[ 0 ] = 0;\r
132 \r
133                         /* Ensure that the above line did generate MemFault and the fault\r
134                          * handler did clear the  ucROTaskFaultTracker[ 0 ]. */\r
135                         configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );\r
136                 }\r
137                 #else\r
138                 {\r
139                         /* Generate an SVC to raise the privilege. Since\r
140                          * configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY is not enabled, the\r
141                          * task will be able to escalate privilege. */\r
142                         portRAISE_PRIVILEGE();\r
143 \r
144                         /* At this point, the task is running privileged. The following\r
145                          * access must not result in Memory Fault. If something goes\r
146                          * wrong and we do get a fault, the execution will stop in fault\r
147                          * handler as ucROTaskFaultTracker[ 0 ] is not set (i.e.\r
148                          * un-expected fault). */\r
149                         ucSharedMemory[ 0 ] = 0;\r
150 \r
151                         /* Lower down the privilege. */\r
152                         portSWITCH_TO_USER_MODE();\r
153 \r
154                         /* Now the task is running unprivileged and therefore an attempt to\r
155                          * write to ucSharedMemory will result in a Memory Fault. Set\r
156                          * ucROTaskFaultTracker[ 0 ] to 1 to tell the Memory Fault Handler\r
157                          * that this is an expected fault. The handler will then be able to\r
158                          * recover from this fault gracefully by jumping to the next\r
159                          * instruction.*/\r
160                         ucROTaskFaultTracker[ 0 ] = 1;\r
161 \r
162                         /* The following must result in Memory Fault since the task is now\r
163                          * running unprivileged. */\r
164                         ucSharedMemory[ 0 ] = 0;\r
165 \r
166                         /* Ensure that the above line did generate MemFault and the fault\r
167                          * handler did clear the  ucROTaskFaultTracker[ 0 ]. */\r
168                         configASSERT( ucROTaskFaultTracker[ 0 ] == 0 );\r
169                 }\r
170                 #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */\r
171 \r
172                 /* Wait for a second. */\r
173                 vTaskDelay( pdMS_TO_TICKS( 1000 ) );\r
174         }\r
175 }\r
176 /*-----------------------------------------------------------*/\r
177 \r
178 static void prvRWAccessTask( void * pvParameters )\r
179 {\r
180         /* Unused parameters. */\r
181         ( void ) pvParameters;\r
182 \r
183         for( ; ; )\r
184         {\r
185                 /* This task has RW access to ucSharedMemory and therefore can write to\r
186                  * it. */\r
187                 ucSharedMemory[ 0 ] = 0;\r
188 \r
189                 /* Wait for a second. */\r
190                 vTaskDelay( pdMS_TO_TICKS( 1000 ) );\r
191         }\r
192 }\r
193 /*-----------------------------------------------------------*/\r
194 \r
195 void vStartMPUDemo( void )\r
196 {\r
197 /**\r
198  * Since stack of a task is protected using MPU, it must satisfy MPU\r
199  * requirements as mentioned at the top of this file.\r
200  */\r
201 static StackType_t xROAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( configMINIMAL_STACK_SIZE * sizeof( StackType_t ) ) ) );\r
202 static StackType_t xRWAccessTaskStack[ configMINIMAL_STACK_SIZE ] __attribute__( ( aligned( configMINIMAL_STACK_SIZE * sizeof( StackType_t ) ) ) );\r
203 TaskParameters_t xROAccessTaskParameters =\r
204 {\r
205         .pvTaskCode             = prvROAccessTask,\r
206         .pcName                 = "ROAccess",\r
207         .usStackDepth   = configMINIMAL_STACK_SIZE,\r
208         .pvParameters   = NULL,\r
209         .uxPriority             = tskIDLE_PRIORITY,\r
210         .puxStackBuffer = xROAccessTaskStack,\r
211         .xRegions               =       {\r
212                                                         { ucSharedMemory,                                       SHARED_MEMORY_SIZE,     portMPU_REGION_PRIVILEGED_READ_WRITE_UNPRIV_READ_ONLY | portMPU_REGION_EXECUTE_NEVER    },\r
213                                                         { ( void * ) ucROTaskFaultTracker,      SHARED_MEMORY_SIZE,     portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER                                                                },\r
214                                                         { 0,                                                            0,                                      0                                                                                                                                                                               },\r
215                                                 }\r
216 };\r
217 TaskParameters_t xRWAccessTaskParameters =\r
218 {\r
219         .pvTaskCode             = prvRWAccessTask,\r
220         .pcName                 = "RWAccess",\r
221         .usStackDepth   = configMINIMAL_STACK_SIZE,\r
222         .pvParameters   = NULL,\r
223         .uxPriority             = tskIDLE_PRIORITY,\r
224         .puxStackBuffer = xRWAccessTaskStack,\r
225         .xRegions               =       {\r
226                                                         { ucSharedMemory,       SHARED_MEMORY_SIZE,     portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER},\r
227                                                         { 0,                            0,                                      0                                                                                                               },\r
228                                                         { 0,                            0,                                      0                                                                                                               },\r
229                                                 }\r
230 };\r
231 \r
232         /* Create an unprivileged task with RO access to ucSharedMemory. */\r
233         xTaskCreateRestricted( &( xROAccessTaskParameters ), NULL );\r
234 \r
235         /* Create an unprivileged task with RW access to ucSharedMemory. */\r
236         xTaskCreateRestricted( &( xRWAccessTaskParameters ), NULL );\r
237 }\r
238 /*-----------------------------------------------------------*/\r
239 \r
240 portDONT_DISCARD void vHandleMemoryFault( uint32_t * pulFaultStackAddress )\r
241 {\r
242 uint32_t ulPC;\r
243 uint16_t usOffendingInstruction;\r
244 \r
245         /* Is this an expected fault? */\r
246         if( ucROTaskFaultTracker[ 0 ] == 1 )\r
247         {\r
248                 /* Read program counter. */\r
249                 ulPC = pulFaultStackAddress[ 6 ];\r
250 \r
251                 /* Read the offending instruction. */\r
252                 usOffendingInstruction = *( uint16_t * )ulPC;\r
253 \r
254                 /* From ARM docs:\r
255                  * If the value of bits[15:11] of the halfword being decoded is one of\r
256                  * the following, the halfword is the first halfword of a 32-bit\r
257                  * instruction:\r
258                  * - 0b11101.\r
259                  * - 0b11110.\r
260                  * - 0b11111.\r
261                  * Otherwise, the halfword is a 16-bit instruction.\r
262                  */\r
263 \r
264                 /* Extract bits[15:11] of the offending instruction. */\r
265                 usOffendingInstruction = usOffendingInstruction & 0xF800;\r
266                 usOffendingInstruction = ( usOffendingInstruction >> 11 );\r
267 \r
268                 /* Determine if the offending instruction is a 32-bit instruction or\r
269                  * a 16-bit instruction. */\r
270                 if( usOffendingInstruction == 0x001F ||\r
271                         usOffendingInstruction == 0x001E ||\r
272                         usOffendingInstruction == 0x001D )\r
273                 {\r
274                         /* Since the offending instruction is a 32-bit instruction,\r
275                          * increment the program counter by 4 to move to the next\r
276                          * instruction. */\r
277                         ulPC += 4;\r
278                 }\r
279                 else\r
280                 {\r
281                         /* Since the offending instruction is a 16-bit instruction,\r
282                          * increment the program counter by 2 to move to the next\r
283                          * instruction. */\r
284                         ulPC += 2;\r
285                 }\r
286 \r
287                 /* Save the new program counter on the stack. */\r
288                 pulFaultStackAddress[ 6 ] = ulPC;\r
289 \r
290                 /* Mark the fault as handled. */\r
291                 ucROTaskFaultTracker[ 0 ] = 0;\r
292         }\r
293         else\r
294         {\r
295                 /* This is an unexpected fault - loop forever. */\r
296                 for( ; ; )\r
297                 {\r
298                 }\r
299         }\r
300 }\r
301 /*-----------------------------------------------------------*/\r