]> begriffs open source - freertos/blob - portable/GCC/ARM_CM4_MPU/port.c
[AUTO][RELEASE]: Bump file header version to "10.4.4"
[freertos] / portable / GCC / ARM_CM4_MPU / port.c
1 /*\r
2  * FreeRTOS Kernel V10.4.4\r
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
8  * this software and associated documentation files (the "Software"), to deal in\r
9  * the Software without restriction, including without limitation the rights to\r
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
11  * the Software, and to permit persons to whom the Software is furnished to do so,\r
12  * subject to the following conditions:\r
13  *\r
14  * The above copyright notice and this permission notice shall be included in all\r
15  * copies or substantial portions of the Software.\r
16  *\r
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
23  *\r
24  * https://www.FreeRTOS.org\r
25  * https://github.com/FreeRTOS\r
26  *\r
27  */\r
28 \r
29 /*-----------------------------------------------------------\r
30 * Implementation of functions defined in portable.h for the ARM CM4 MPU port.\r
31 *----------------------------------------------------------*/\r
32 \r
33 /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining\r
34  * all the API functions to use the MPU wrappers.  That should only be done when\r
35  * task.h is included from an application file. */\r
36 #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
37 \r
38 /* Scheduler includes. */\r
39 #include "FreeRTOS.h"\r
40 #include "task.h"\r
41 \r
42 #ifndef __VFP_FP__\r
43     #error This port can only be used when the project options are configured to enable hardware floating point support.\r
44 #endif\r
45 \r
46 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE\r
47 \r
48 #ifndef configSYSTICK_CLOCK_HZ\r
49     #define configSYSTICK_CLOCK_HZ    configCPU_CLOCK_HZ\r
50     /* Ensure the SysTick is clocked at the same frequency as the core. */\r
51     #define portNVIC_SYSTICK_CLK      ( 1UL << 2UL )\r
52 #else\r
53 \r
54 /* The way the SysTick is clocked is not modified in case it is not the same\r
55  * as the core. */\r
56     #define portNVIC_SYSTICK_CLK    ( 0 )\r
57 #endif\r
58 \r
59 /* Constants required to access and manipulate the NVIC. */\r
60 #define portNVIC_SYSTICK_CTRL_REG                 ( *( ( volatile uint32_t * ) 0xe000e010 ) )\r
61 #define portNVIC_SYSTICK_LOAD_REG                 ( *( ( volatile uint32_t * ) 0xe000e014 ) )\r
62 #define portNVIC_SYSTICK_CURRENT_VALUE_REG        ( *( ( volatile uint32_t * ) 0xe000e018 ) )\r
63 #define portNVIC_SHPR3_REG                        ( *( ( volatile uint32_t * ) 0xe000ed20 ) )\r
64 #define portNVIC_SHPR2_REG                        ( *( ( volatile uint32_t * ) 0xe000ed1c ) )\r
65 #define portNVIC_SYS_CTRL_STATE_REG               ( *( ( volatile uint32_t * ) 0xe000ed24 ) )\r
66 #define portNVIC_MEM_FAULT_ENABLE                 ( 1UL << 16UL )\r
67 \r
68 /* Constants required to access and manipulate the MPU. */\r
69 #define portMPU_TYPE_REG                          ( *( ( volatile uint32_t * ) 0xe000ed90 ) )\r
70 #define portMPU_REGION_BASE_ADDRESS_REG           ( *( ( volatile uint32_t * ) 0xe000ed9C ) )\r
71 #define portMPU_REGION_ATTRIBUTE_REG              ( *( ( volatile uint32_t * ) 0xe000edA0 ) )\r
72 #define portMPU_CTRL_REG                          ( *( ( volatile uint32_t * ) 0xe000ed94 ) )\r
73 #define portEXPECTED_MPU_TYPE_VALUE               ( portTOTAL_NUM_REGIONS << 8UL )\r
74 #define portMPU_ENABLE                            ( 0x01UL )\r
75 #define portMPU_BACKGROUND_ENABLE                 ( 1UL << 2UL )\r
76 #define portPRIVILEGED_EXECUTION_START_ADDRESS    ( 0UL )\r
77 #define portMPU_REGION_VALID                      ( 0x10UL )\r
78 #define portMPU_REGION_ENABLE                     ( 0x01UL )\r
79 #define portPERIPHERALS_START_ADDRESS             0x40000000UL\r
80 #define portPERIPHERALS_END_ADDRESS               0x5FFFFFFFUL\r
81 \r
82 /* Constants required to access and manipulate the SysTick. */\r
83 #define portNVIC_SYSTICK_INT                      ( 0x00000002UL )\r
84 #define portNVIC_SYSTICK_ENABLE                   ( 0x00000001UL )\r
85 #define portNVIC_PENDSV_PRI                       ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )\r
86 #define portNVIC_SYSTICK_PRI                      ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )\r
87 #define portNVIC_SVC_PRI                          ( ( ( uint32_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY - 1UL ) << 24UL )\r
88 \r
89 /* Constants required to manipulate the VFP. */\r
90 #define portFPCCR                                 ( ( volatile uint32_t * ) 0xe000ef34UL ) /* Floating point context control register. */\r
91 #define portASPEN_AND_LSPEN_BITS                  ( 0x3UL << 30UL )\r
92 \r
93 /* Constants required to set up the initial stack. */\r
94 #define portINITIAL_XPSR                          ( 0x01000000UL )\r
95 #define portINITIAL_EXC_RETURN                    ( 0xfffffffdUL )\r
96 #define portINITIAL_CONTROL_IF_UNPRIVILEGED       ( 0x03 )\r
97 #define portINITIAL_CONTROL_IF_PRIVILEGED         ( 0x02 )\r
98 \r
99 /* Constants required to check the validity of an interrupt priority. */\r
100 #define portFIRST_USER_INTERRUPT_NUMBER           ( 16 )\r
101 #define portNVIC_IP_REGISTERS_OFFSET_16           ( 0xE000E3F0 )\r
102 #define portAIRCR_REG                             ( *( ( volatile uint32_t * ) 0xE000ED0C ) )\r
103 #define portMAX_8_BIT_VALUE                       ( ( uint8_t ) 0xff )\r
104 #define portTOP_BIT_OF_BYTE                       ( ( uint8_t ) 0x80 )\r
105 #define portMAX_PRIGROUP_BITS                     ( ( uint8_t ) 7 )\r
106 #define portPRIORITY_GROUP_MASK                   ( 0x07UL << 8UL )\r
107 #define portPRIGROUP_SHIFT                        ( 8UL )\r
108 \r
109 /* Offsets in the stack to the parameters when inside the SVC handler. */\r
110 #define portOFFSET_TO_PC                          ( 6 )\r
111 \r
112 /* For strict compliance with the Cortex-M spec the task start address should\r
113  * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */\r
114 #define portSTART_ADDRESS_MASK                    ( ( StackType_t ) 0xfffffffeUL )\r
115 \r
116 /*\r
117  * Configure a number of standard MPU regions that are used by all tasks.\r
118  */\r
119 static void prvSetupMPU( void ) PRIVILEGED_FUNCTION;\r
120 \r
121 /*\r
122  * Return the smallest MPU region size that a given number of bytes will fit\r
123  * into.  The region size is returned as the value that should be programmed\r
124  * into the region attribute register for that region.\r
125  */\r
126 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVILEGED_FUNCTION;\r
127 \r
128 /*\r
129  * Setup the timer to generate the tick interrupts.  The implementation in this\r
130  * file is weak to allow application writers to change the timer used to\r
131  * generate the tick interrupt.\r
132  */\r
133 void vPortSetupTimerInterrupt( void );\r
134 \r
135 /*\r
136  * Standard FreeRTOS exception handlers.\r
137  */\r
138 void xPortPendSVHandler( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;\r
139 void xPortSysTickHandler( void ) PRIVILEGED_FUNCTION;\r
140 void vPortSVCHandler( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;\r
141 \r
142 /*\r
143  * Starts the scheduler by restoring the context of the first task to run.\r
144  */\r
145 static void prvRestoreContextOfFirstTask( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;\r
146 \r
147 /*\r
148  * C portion of the SVC handler.  The SVC handler is split between an asm entry\r
149  * and a C wrapper for simplicity of coding and maintenance.\r
150  */\r
151 static void prvSVCHandler( uint32_t * pulRegisters ) __attribute__( ( noinline ) ) PRIVILEGED_FUNCTION;\r
152 \r
153 /*\r
154  * Function to enable the VFP.\r
155  */\r
156 static void vPortEnableVFP( void ) __attribute__( ( naked ) );\r
157 \r
158 /**\r
159  * @brief Checks whether or not the processor is privileged.\r
160  *\r
161  * @return 1 if the processor is already privileged, 0 otherwise.\r
162  */\r
163 BaseType_t xIsPrivileged( void ) __attribute__( ( naked ) );\r
164 \r
165 /**\r
166  * @brief Lowers the privilege level by setting the bit 0 of the CONTROL\r
167  * register.\r
168  *\r
169  * Bit 0 of the CONTROL register defines the privilege level of Thread Mode.\r
170  *  Bit[0] = 0 --> The processor is running privileged\r
171  *  Bit[0] = 1 --> The processor is running unprivileged.\r
172  */\r
173 void vResetPrivilege( void ) __attribute__( ( naked ) );\r
174 \r
175 /**\r
176  * @brief Calls the port specific code to raise the privilege.\r
177  *\r
178  * @return pdFALSE if privilege was raised, pdTRUE otherwise.\r
179  */\r
180 extern BaseType_t xPortRaisePrivilege( void );\r
181 \r
182 /**\r
183  * @brief If xRunningPrivileged is not pdTRUE, calls the port specific\r
184  * code to reset the privilege, otherwise does nothing.\r
185  */\r
186 extern void vPortResetPrivilege( BaseType_t xRunningPrivileged );\r
187 /*-----------------------------------------------------------*/\r
188 \r
189 /* Each task maintains its own interrupt status in the critical nesting\r
190  * variable.  Note this is not saved as part of the task context as context\r
191  * switches can only occur when uxCriticalNesting is zero. */\r
192 static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;\r
193 \r
194 /*\r
195  * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure\r
196  * FreeRTOS API functions are not called from interrupts that have been assigned\r
197  * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
198  */\r
199 #if ( configASSERT_DEFINED == 1 )\r
200     static uint8_t ucMaxSysCallPriority = 0;\r
201     static uint32_t ulMaxPRIGROUPValue = 0;\r
202     static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;\r
203 #endif /* configASSERT_DEFINED */\r
204 \r
205 /*-----------------------------------------------------------*/\r
206 \r
207 /*\r
208  * See header file for description.\r
209  */\r
210 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,\r
211                                      TaskFunction_t pxCode,\r
212                                      void * pvParameters,\r
213                                      BaseType_t xRunPrivileged )\r
214 {\r
215     /* Simulate the stack frame as it would be created by a context switch\r
216      * interrupt. */\r
217     pxTopOfStack--;                                                      /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */\r
218     *pxTopOfStack = portINITIAL_XPSR;                                    /* xPSR */\r
219     pxTopOfStack--;\r
220     *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */\r
221     pxTopOfStack--;\r
222     *pxTopOfStack = 0;                                                   /* LR */\r
223     pxTopOfStack -= 5;                                                   /* R12, R3, R2 and R1. */\r
224     *pxTopOfStack = ( StackType_t ) pvParameters;                        /* R0 */\r
225 \r
226     /* A save method is being used that requires each task to maintain its\r
227      * own exec return value. */\r
228     pxTopOfStack--;\r
229     *pxTopOfStack = portINITIAL_EXC_RETURN;\r
230 \r
231     pxTopOfStack -= 9; /* R11, R10, R9, R8, R7, R6, R5 and R4. */\r
232 \r
233     if( xRunPrivileged == pdTRUE )\r
234     {\r
235         *pxTopOfStack = portINITIAL_CONTROL_IF_PRIVILEGED;\r
236     }\r
237     else\r
238     {\r
239         *pxTopOfStack = portINITIAL_CONTROL_IF_UNPRIVILEGED;\r
240     }\r
241 \r
242     return pxTopOfStack;\r
243 }\r
244 /*-----------------------------------------------------------*/\r
245 \r
246 void vPortSVCHandler( void )\r
247 {\r
248     /* Assumes psp was in use. */\r
249     __asm volatile\r
250     (\r
251         #ifndef USE_PROCESS_STACK   /* Code should not be required if a main() is using the process stack. */\r
252             "   tst lr, #4                                              \n"\r
253             "   ite eq                                                  \n"\r
254             "   mrseq r0, msp                                   \n"\r
255             "   mrsne r0, psp                                   \n"\r
256         #else\r
257             "   mrs r0, psp                                             \n"\r
258         #endif\r
259         "       b %0                                                    \n"\r
260         ::"i" ( prvSVCHandler ) : "r0", "memory"\r
261     );\r
262 }\r
263 /*-----------------------------------------------------------*/\r
264 \r
265 static void prvSVCHandler( uint32_t * pulParam )\r
266 {\r
267     uint8_t ucSVCNumber;\r
268     uint32_t ulPC;\r
269 \r
270     #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )\r
271         #if defined( __ARMCC_VERSION )\r
272 \r
273             /* Declaration when these variable are defined in code instead of being\r
274              * exported from linker scripts. */\r
275             extern uint32_t * __syscalls_flash_start__;\r
276             extern uint32_t * __syscalls_flash_end__;\r
277         #else\r
278             /* Declaration when these variable are exported from linker scripts. */\r
279             extern uint32_t __syscalls_flash_start__[];\r
280             extern uint32_t __syscalls_flash_end__[];\r
281         #endif /* #if defined( __ARMCC_VERSION ) */\r
282     #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */\r
283 \r
284     /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR.  The first\r
285      * argument (r0) is pulParam[ 0 ]. */\r
286     ulPC = pulParam[ portOFFSET_TO_PC ];\r
287     ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];\r
288 \r
289     switch( ucSVCNumber )\r
290     {\r
291         case portSVC_START_SCHEDULER:\r
292             portNVIC_SHPR2_REG |= portNVIC_SVC_PRI;\r
293             prvRestoreContextOfFirstTask();\r
294             break;\r
295 \r
296         case portSVC_YIELD:\r
297             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
298 \r
299             /* Barriers are normally not required\r
300              * but do ensure the code is completely\r
301              * within the specified behaviour for the\r
302              * architecture. */\r
303             __asm volatile ( "dsb" ::: "memory" );\r
304             __asm volatile ( "isb" );\r
305 \r
306             break;\r
307 \r
308             #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )\r
309                 case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the\r
310                                                * svc was raised from any of the\r
311                                                * system calls. */\r
312 \r
313                     if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&\r
314                         ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )\r
315                     {\r
316                         __asm volatile\r
317                         (\r
318                             "   mrs r1, control         \n"/* Obtain current control value. */\r
319                             "   bic r1, #1                      \n"/* Set privilege bit. */\r
320                             "   msr control, r1         \n"/* Write back new control value. */\r
321                             ::: "r1", "memory"\r
322                         );\r
323                     }\r
324 \r
325                     break;\r
326             #else /* if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */\r
327                 case portSVC_RAISE_PRIVILEGE:\r
328                     __asm volatile\r
329                     (\r
330                         "       mrs r1, control         \n"/* Obtain current control value. */\r
331                         "       bic r1, #1                      \n"/* Set privilege bit. */\r
332                         "       msr control, r1         \n"/* Write back new control value. */\r
333                         ::: "r1", "memory"\r
334                     );\r
335                     break;\r
336                     #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */\r
337 \r
338                 default: /* Unknown SVC call. */\r
339                     break;\r
340     }\r
341 }\r
342 /*-----------------------------------------------------------*/\r
343 \r
344 static void prvRestoreContextOfFirstTask( void )\r
345 {\r
346     __asm volatile\r
347     (\r
348         "       ldr r0, =0xE000ED08                             \n"/* Use the NVIC offset register to locate the stack. */\r
349         "       ldr r0, [r0]                                    \n"\r
350         "       ldr r0, [r0]                                    \n"\r
351         "       msr msp, r0                                             \n"/* Set the msp back to the start of the stack. */\r
352         "       ldr     r3, pxCurrentTCBConst2          \n"/* Restore the context. */\r
353         "       ldr r1, [r3]                                    \n"\r
354         "       ldr r0, [r1]                                    \n"/* The first item in the TCB is the task top of stack. */\r
355         "       add r1, r1, #4                                  \n"/* Move onto the second item in the TCB... */\r
356         "                                                                       \n"\r
357         "       dmb                                                             \n"/* Complete outstanding transfers before disabling MPU. */\r
358         "       ldr r2, =0xe000ed94                             \n"/* MPU_CTRL register. */\r
359         "       ldr r3, [r2]                                    \n"/* Read the value of MPU_CTRL. */\r
360         "       bic r3, #1                                              \n"/* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */\r
361         "       str r3, [r2]                                    \n"/* Disable MPU. */\r
362         "                                                                       \n"\r
363         "       ldr r2, =0xe000ed9c                             \n"/* Region Base Address register. */\r
364         "       ldmia r1!, {r4-r11}                             \n"/* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
365         "       stmia r2, {r4-r11}                              \n"/* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
366         "                                                                       \n"\r
367         #if ( portTOTAL_NUM_REGIONS == 16 )\r
368             "   ldmia r1!, {r4-r11}                             \n"/* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */\r
369             "   stmia r2, {r4-r11}                              \n"/* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */\r
370             "   ldmia r1!, {r4-r11}                             \n"/* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */\r
371             "   stmia r2, {r4-r11}                              \n"/* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */\r
372         #endif /* portTOTAL_NUM_REGIONS == 16. */\r
373         "                                                                       \n"\r
374         "       ldr r2, =0xe000ed94                             \n"/* MPU_CTRL register. */\r
375         "       ldr r3, [r2]                                    \n"/* Read the value of MPU_CTRL. */\r
376         "       orr r3, #1                                              \n"/* r3 = r3 | 1 i.e. Set the bit 0 in r3. */\r
377         "       str r3, [r2]                                    \n"/* Enable MPU. */\r
378         "       dsb                                                             \n"/* Force memory writes before continuing. */\r
379         "                                                                       \n"\r
380         "       ldmia r0!, {r3-r11, r14}                \n"/* Pop the registers that are not automatically saved on exception entry. */\r
381         "       msr control, r3                                 \n"\r
382         "       msr psp, r0                                             \n"/* Restore the task stack pointer. */\r
383         "       mov r0, #0                                              \n"\r
384         "       msr     basepri, r0                                     \n"\r
385         "       bx r14                                                  \n"\r
386         "                                                                       \n"\r
387         "       .align 4                                                \n"\r
388         "pxCurrentTCBConst2: .word pxCurrentTCB \n"\r
389     );\r
390 }\r
391 /*-----------------------------------------------------------*/\r
392 \r
393 /*\r
394  * See header file for description.\r
395  */\r
396 BaseType_t xPortStartScheduler( void )\r
397 {\r
398     /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.  See\r
399      * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */\r
400     configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) );\r
401 \r
402     #if ( configASSERT_DEFINED == 1 )\r
403         {\r
404             volatile uint32_t ulOriginalPriority;\r
405             volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );\r
406             volatile uint8_t ucMaxPriorityValue;\r
407 \r
408             /* Determine the maximum priority from which ISR safe FreeRTOS API\r
409              * functions can be called.  ISR safe functions are those that end in\r
410              * "FromISR".  FreeRTOS maintains separate thread and ISR API functions to\r
411              * ensure interrupt entry is as fast and simple as possible.\r
412              *\r
413              * Save the interrupt priority value that is about to be clobbered. */\r
414             ulOriginalPriority = *pucFirstUserPriorityRegister;\r
415 \r
416             /* Determine the number of priority bits available.  First write to all\r
417              * possible bits. */\r
418             *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;\r
419 \r
420             /* Read the value back to see how many bits stuck. */\r
421             ucMaxPriorityValue = *pucFirstUserPriorityRegister;\r
422 \r
423             /* Use the same mask on the maximum system call priority. */\r
424             ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;\r
425 \r
426             /* Calculate the maximum acceptable priority group value for the number\r
427              * of bits read back. */\r
428             ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;\r
429 \r
430             while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )\r
431             {\r
432                 ulMaxPRIGROUPValue--;\r
433                 ucMaxPriorityValue <<= ( uint8_t ) 0x01;\r
434             }\r
435 \r
436             #ifdef __NVIC_PRIO_BITS\r
437                 {\r
438                     /* Check the CMSIS configuration that defines the number of\r
439                      * priority bits matches the number of priority bits actually queried\r
440                      * from the hardware. */\r
441                     configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );\r
442                 }\r
443             #endif\r
444 \r
445             #ifdef configPRIO_BITS\r
446                 {\r
447                     /* Check the FreeRTOS configuration that defines the number of\r
448                      * priority bits matches the number of priority bits actually queried\r
449                      * from the hardware. */\r
450                     configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );\r
451                 }\r
452             #endif\r
453 \r
454             /* Shift the priority group value back to its position within the AIRCR\r
455              * register. */\r
456             ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;\r
457             ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;\r
458 \r
459             /* Restore the clobbered interrupt priority register to its original\r
460              * value. */\r
461             *pucFirstUserPriorityRegister = ulOriginalPriority;\r
462         }\r
463     #endif /* conifgASSERT_DEFINED */\r
464 \r
465     /* Make PendSV and SysTick the same priority as the kernel, and the SVC\r
466      * handler higher priority so it can be used to exit a critical section (where\r
467      * lower priorities are masked). */\r
468     portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;\r
469     portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;\r
470 \r
471     /* Configure the regions in the MPU that are common to all tasks. */\r
472     prvSetupMPU();\r
473 \r
474     /* Start the timer that generates the tick ISR.  Interrupts are disabled\r
475      * here already. */\r
476     vPortSetupTimerInterrupt();\r
477 \r
478     /* Initialise the critical nesting count ready for the first task. */\r
479     uxCriticalNesting = 0;\r
480 \r
481     /* Ensure the VFP is enabled - it should be anyway. */\r
482     vPortEnableVFP();\r
483 \r
484     /* Lazy save always. */\r
485     *( portFPCCR ) |= portASPEN_AND_LSPEN_BITS;\r
486 \r
487     /* Start the first task.  This also clears the bit that indicates the FPU is\r
488      * in use in case the FPU was used before the scheduler was started - which\r
489      * would otherwise result in the unnecessary leaving of space in the SVC stack\r
490      * for lazy saving of FPU registers. */\r
491     __asm volatile (\r
492         " ldr r0, =0xE000ED08   \n"/* Use the NVIC offset register to locate the stack. */\r
493         " ldr r0, [r0]                  \n"\r
494         " ldr r0, [r0]                  \n"\r
495         " msr msp, r0                   \n"/* Set the msp back to the start of the stack. */\r
496         " mov r0, #0                    \n"/* Clear the bit that indicates the FPU is in use, see comment above. */\r
497         " msr control, r0               \n"\r
498         " cpsie i                               \n"/* Globally enable interrupts. */\r
499         " cpsie f                               \n"\r
500         " dsb                                   \n"\r
501         " isb                                   \n"\r
502         " svc %0                                \n"/* System call to start first task. */\r
503         " nop                                   \n"\r
504         " .ltorg                                \n"\r
505         ::"i" ( portSVC_START_SCHEDULER ) : "memory" );\r
506 \r
507     /* Should not get here! */\r
508     return 0;\r
509 }\r
510 /*-----------------------------------------------------------*/\r
511 \r
512 void vPortEndScheduler( void )\r
513 {\r
514     /* Not implemented in ports where there is nothing to return to.\r
515      * Artificially force an assert. */\r
516     configASSERT( uxCriticalNesting == 1000UL );\r
517 }\r
518 /*-----------------------------------------------------------*/\r
519 \r
520 void vPortEnterCritical( void )\r
521 {\r
522     BaseType_t xRunningPrivileged = xPortRaisePrivilege();\r
523 \r
524     portDISABLE_INTERRUPTS();\r
525     uxCriticalNesting++;\r
526 \r
527     vPortResetPrivilege( xRunningPrivileged );\r
528 }\r
529 /*-----------------------------------------------------------*/\r
530 \r
531 void vPortExitCritical( void )\r
532 {\r
533     BaseType_t xRunningPrivileged = xPortRaisePrivilege();\r
534 \r
535     configASSERT( uxCriticalNesting );\r
536     uxCriticalNesting--;\r
537 \r
538     if( uxCriticalNesting == 0 )\r
539     {\r
540         portENABLE_INTERRUPTS();\r
541     }\r
542 \r
543     vPortResetPrivilege( xRunningPrivileged );\r
544 }\r
545 /*-----------------------------------------------------------*/\r
546 \r
547 void xPortPendSVHandler( void )\r
548 {\r
549     /* This is a naked function. */\r
550 \r
551     __asm volatile\r
552     (\r
553         "       mrs r0, psp                                                     \n"\r
554         "       isb                                                                     \n"\r
555         "                                                                               \n"\r
556         "       ldr     r3, pxCurrentTCBConst                   \n"/* Get the location of the current TCB. */\r
557         "       ldr     r2, [r3]                                                \n"\r
558         "                                                                               \n"\r
559         "       tst r14, #0x10                                          \n"/* Is the task using the FPU context?  If so, push high vfp registers. */\r
560         "       it eq                                                           \n"\r
561         "       vstmdbeq r0!, {s16-s31}                         \n"\r
562         "                                                                               \n"\r
563         "       mrs r1, control                                         \n"\r
564         "       stmdb r0!, {r1, r4-r11, r14}            \n"/* Save the remaining registers. */\r
565         "       str r0, [r2]                                            \n"/* Save the new top of stack into the first member of the TCB. */\r
566         "                                                                               \n"\r
567         "       stmdb sp!, {r0, r3}                                     \n"\r
568         "       mov r0, %0                                                      \n"\r
569         "       msr basepri, r0                                         \n"\r
570         "       dsb                                                                     \n"\r
571         "       isb                                                                     \n"\r
572         "       bl vTaskSwitchContext                           \n"\r
573         "       mov r0, #0                                                      \n"\r
574         "       msr basepri, r0                                         \n"\r
575         "       ldmia sp!, {r0, r3}                                     \n"\r
576         "                                                                               \n"/* Restore the context. */\r
577         "       ldr r1, [r3]                                            \n"\r
578         "       ldr r0, [r1]                                            \n"/* The first item in the TCB is the task top of stack. */\r
579         "       add r1, r1, #4                                          \n"/* Move onto the second item in the TCB... */\r
580         "                                                                               \n"\r
581         "       dmb                                                                     \n"/* Complete outstanding transfers before disabling MPU. */\r
582         "       ldr r2, =0xe000ed94                                     \n"/* MPU_CTRL register. */\r
583         "       ldr r3, [r2]                                            \n"/* Read the value of MPU_CTRL. */\r
584         "       bic r3, #1                                                      \n"/* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */\r
585         "       str r3, [r2]                                            \n"/* Disable MPU. */\r
586         "                                                                               \n"\r
587         "       ldr r2, =0xe000ed9c                                     \n"/* Region Base Address register. */\r
588         "       ldmia r1!, {r4-r11}                                     \n"/* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
589         "       stmia r2, {r4-r11}                                      \n"/* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
590         "                                                                               \n"\r
591         #if ( portTOTAL_NUM_REGIONS == 16 )\r
592             "   ldmia r1!, {r4-r11}                                     \n"/* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */\r
593             "   stmia r2, {r4-r11}                                      \n"/* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */\r
594             "   ldmia r1!, {r4-r11}                                     \n"/* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */\r
595             "   stmia r2, {r4-r11}                                      \n"/* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */\r
596         #endif /* portTOTAL_NUM_REGIONS == 16. */\r
597         "                                                                               \n"\r
598         "       ldr r2, =0xe000ed94                                     \n"/* MPU_CTRL register. */\r
599         "       ldr r3, [r2]                                            \n"/* Read the value of MPU_CTRL. */\r
600         "       orr r3, #1                                                      \n"/* r3 = r3 | 1 i.e. Set the bit 0 in r3. */\r
601         "       str r3, [r2]                                            \n"/* Enable MPU. */\r
602         "       dsb                                                                     \n"/* Force memory writes before continuing. */\r
603         "                                                                               \n"\r
604         "       ldmia r0!, {r3-r11, r14}                        \n"/* Pop the registers that are not automatically saved on exception entry. */\r
605         "       msr control, r3                                         \n"\r
606         "                                                                               \n"\r
607         "       tst r14, #0x10                                          \n"/* Is the task using the FPU context?  If so, pop the high vfp registers too. */\r
608         "       it eq                                                           \n"\r
609         "       vldmiaeq r0!, {s16-s31}                         \n"\r
610         "                                                                               \n"\r
611         "       msr psp, r0                                                     \n"\r
612         "       bx r14                                                          \n"\r
613         "                                                                               \n"\r
614         "       .align 4                                                        \n"\r
615         "pxCurrentTCBConst: .word pxCurrentTCB  \n"\r
616         ::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )\r
617     );\r
618 }\r
619 /*-----------------------------------------------------------*/\r
620 \r
621 void xPortSysTickHandler( void )\r
622 {\r
623     uint32_t ulDummy;\r
624 \r
625     ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();\r
626     {\r
627         /* Increment the RTOS tick. */\r
628         if( xTaskIncrementTick() != pdFALSE )\r
629         {\r
630             /* Pend a context switch. */\r
631             portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;\r
632         }\r
633     }\r
634     portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );\r
635 }\r
636 /*-----------------------------------------------------------*/\r
637 \r
638 /*\r
639  * Setup the systick timer to generate the tick interrupts at the required\r
640  * frequency.\r
641  */\r
642 __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void )\r
643 {\r
644     /* Stop and clear the SysTick. */\r
645     portNVIC_SYSTICK_CTRL_REG = 0UL;\r
646     portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;\r
647 \r
648     /* Configure SysTick to interrupt at the requested rate. */\r
649     portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;\r
650     portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE );\r
651 }\r
652 /*-----------------------------------------------------------*/\r
653 \r
654 /* This is a naked function. */\r
655 static void vPortEnableVFP( void )\r
656 {\r
657     __asm volatile\r
658     (\r
659         "       ldr.w r0, =0xE000ED88           \n"/* The FPU enable bits are in the CPACR. */\r
660         "       ldr r1, [r0]                            \n"\r
661         "                                                               \n"\r
662         "       orr r1, r1, #( 0xf << 20 )      \n"/* Enable CP10 and CP11 coprocessors, then save back. */\r
663         "       str r1, [r0]                            \n"\r
664         "       bx r14                                          \n"\r
665         "       .ltorg                                          \n"\r
666     );\r
667 }\r
668 /*-----------------------------------------------------------*/\r
669 \r
670 static void prvSetupMPU( void )\r
671 {\r
672     #if defined( __ARMCC_VERSION )\r
673 \r
674         /* Declaration when these variable are defined in code instead of being\r
675          * exported from linker scripts. */\r
676         extern uint32_t * __privileged_functions_start__;\r
677         extern uint32_t * __privileged_functions_end__;\r
678         extern uint32_t * __FLASH_segment_start__;\r
679         extern uint32_t * __FLASH_segment_end__;\r
680         extern uint32_t * __privileged_data_start__;\r
681         extern uint32_t * __privileged_data_end__;\r
682     #else\r
683         /* Declaration when these variable are exported from linker scripts. */\r
684         extern uint32_t __privileged_functions_start__[];\r
685         extern uint32_t __privileged_functions_end__[];\r
686         extern uint32_t __FLASH_segment_start__[];\r
687         extern uint32_t __FLASH_segment_end__[];\r
688         extern uint32_t __privileged_data_start__[];\r
689         extern uint32_t __privileged_data_end__[];\r
690     #endif /* if defined( __ARMCC_VERSION ) */\r
691 \r
692     /* The only permitted number of regions are 8 or 16. */\r
693     configASSERT( ( portTOTAL_NUM_REGIONS == 8 ) || ( portTOTAL_NUM_REGIONS == 16 ) );\r
694 \r
695     /* Ensure that the configTOTAL_MPU_REGIONS is configured correctly. */\r
696     configASSERT( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE );\r
697 \r
698     /* Check the expected MPU is present. */\r
699     if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )\r
700     {\r
701         /* First setup the unprivileged flash for unprivileged read only access. */\r
702         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */\r
703                                           ( portMPU_REGION_VALID ) |\r
704                                           ( portUNPRIVILEGED_FLASH_REGION );\r
705 \r
706         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) |\r
707                                        ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
708                                        ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) |\r
709                                        ( portMPU_REGION_ENABLE );\r
710 \r
711         /* Setup the privileged flash for privileged only access.  This is where\r
712          * the kernel code is placed. */\r
713         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_functions_start__ ) | /* Base address. */\r
714                                           ( portMPU_REGION_VALID ) |\r
715                                           ( portPRIVILEGED_FLASH_REGION );\r
716 \r
717         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) |\r
718                                        ( ( configTEX_S_C_B_FLASH & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
719                                        ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) |\r
720                                        ( portMPU_REGION_ENABLE );\r
721 \r
722         /* Setup the privileged data RAM region.  This is where the kernel data\r
723          * is placed. */\r
724         portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */\r
725                                           ( portMPU_REGION_VALID ) |\r
726                                           ( portPRIVILEGED_RAM_REGION );\r
727 \r
728         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |\r
729                                        ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
730                                        prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |\r
731                                        ( portMPU_REGION_ENABLE );\r
732 \r
733         /* By default allow everything to access the general peripherals.  The\r
734          * system peripherals and registers are protected. */\r
735         portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |\r
736                                           ( portMPU_REGION_VALID ) |\r
737                                           ( portGENERAL_PERIPHERALS_REGION );\r
738 \r
739         portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER ) |\r
740                                        ( prvGetMPURegionSizeSetting( portPERIPHERALS_END_ADDRESS - portPERIPHERALS_START_ADDRESS ) ) |\r
741                                        ( portMPU_REGION_ENABLE );\r
742 \r
743         /* Enable the memory fault exception. */\r
744         portNVIC_SYS_CTRL_STATE_REG |= portNVIC_MEM_FAULT_ENABLE;\r
745 \r
746         /* Enable the MPU with the background region configured. */\r
747         portMPU_CTRL_REG |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE );\r
748     }\r
749 }\r
750 /*-----------------------------------------------------------*/\r
751 \r
752 static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )\r
753 {\r
754     uint32_t ulRegionSize, ulReturnValue = 4;\r
755 \r
756     /* 32 is the smallest region size, 31 is the largest valid value for\r
757      * ulReturnValue. */\r
758     for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )\r
759     {\r
760         if( ulActualSizeInBytes <= ulRegionSize )\r
761         {\r
762             break;\r
763         }\r
764         else\r
765         {\r
766             ulReturnValue++;\r
767         }\r
768     }\r
769 \r
770     /* Shift the code by one before returning so it can be written directly\r
771      * into the the correct bit position of the attribute register. */\r
772     return( ulReturnValue << 1UL );\r
773 }\r
774 /*-----------------------------------------------------------*/\r
775 \r
776 BaseType_t xIsPrivileged( void ) /* __attribute__ (( naked )) */\r
777 {\r
778     __asm volatile\r
779     (\r
780         "       mrs r0, control                                                 \n"/* r0 = CONTROL. */\r
781         "       tst r0, #1                                                              \n"/* Perform r0 & 1 (bitwise AND) and update the conditions flag. */\r
782         "       ite ne                                                                  \n"\r
783         "       movne r0, #0                                                    \n"/* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */\r
784         "       moveq r0, #1                                                    \n"/* CONTROL[0]==0. Return true to indicate that the processor is privileged. */\r
785         "       bx lr                                                                   \n"/* Return. */\r
786         "                                                                                       \n"\r
787         "       .align 4                                                                \n"\r
788         ::: "r0", "memory"\r
789     );\r
790 }\r
791 /*-----------------------------------------------------------*/\r
792 \r
793 void vResetPrivilege( void ) /* __attribute__ (( naked )) */\r
794 {\r
795     __asm volatile\r
796     (\r
797         "       mrs r0, control                                                 \n"/* r0 = CONTROL. */\r
798         "       orr r0, #1                                                              \n"/* r0 = r0 | 1. */\r
799         "       msr control, r0                                                 \n"/* CONTROL = r0. */\r
800         "       bx lr                                                                   \n"/* Return to the caller. */\r
801         ::: "r0", "memory"\r
802     );\r
803 }\r
804 /*-----------------------------------------------------------*/\r
805 \r
806 void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,\r
807                                 const struct xMEMORY_REGION * const xRegions,\r
808                                 StackType_t * pxBottomOfStack,\r
809                                 uint32_t ulStackDepth )\r
810 {\r
811     #if defined( __ARMCC_VERSION )\r
812 \r
813         /* Declaration when these variable are defined in code instead of being\r
814          * exported from linker scripts. */\r
815         extern uint32_t * __SRAM_segment_start__;\r
816         extern uint32_t * __SRAM_segment_end__;\r
817         extern uint32_t * __privileged_data_start__;\r
818         extern uint32_t * __privileged_data_end__;\r
819     #else\r
820         /* Declaration when these variable are exported from linker scripts. */\r
821         extern uint32_t __SRAM_segment_start__[];\r
822         extern uint32_t __SRAM_segment_end__[];\r
823         extern uint32_t __privileged_data_start__[];\r
824         extern uint32_t __privileged_data_end__[];\r
825     #endif /* if defined( __ARMCC_VERSION ) */\r
826 \r
827     int32_t lIndex;\r
828     uint32_t ul;\r
829 \r
830     if( xRegions == NULL )\r
831     {\r
832         /* No MPU regions are specified so allow access to all RAM. */\r
833         xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =\r
834             ( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */\r
835             ( portMPU_REGION_VALID ) |\r
836             ( portSTACK_REGION );\r
837 \r
838         xMPUSettings->xRegion[ 0 ].ulRegionAttribute =\r
839             ( portMPU_REGION_READ_WRITE ) |\r
840             ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
841             ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |\r
842             ( portMPU_REGION_ENABLE );\r
843 \r
844         /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have\r
845          * just removed the privileged only parameters. */\r
846         xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =\r
847             ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */\r
848             ( portMPU_REGION_VALID ) |\r
849             ( portSTACK_REGION + 1 );\r
850 \r
851         xMPUSettings->xRegion[ 1 ].ulRegionAttribute =\r
852             ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |\r
853             ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
854             prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |\r
855             ( portMPU_REGION_ENABLE );\r
856 \r
857         /* Invalidate all other regions. */\r
858         for( ul = 2; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )\r
859         {\r
860             xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;\r
861             xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;\r
862         }\r
863     }\r
864     else\r
865     {\r
866         /* This function is called automatically when the task is created - in\r
867          * which case the stack region parameters will be valid.  At all other\r
868          * times the stack parameters will not be valid and it is assumed that the\r
869          * stack region has already been configured. */\r
870         if( ulStackDepth > 0 )\r
871         {\r
872             /* Define the region that allows access to the stack. */\r
873             xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =\r
874                 ( ( uint32_t ) pxBottomOfStack ) |\r
875                 ( portMPU_REGION_VALID ) |\r
876                 ( portSTACK_REGION ); /* Region number. */\r
877 \r
878             xMPUSettings->xRegion[ 0 ].ulRegionAttribute =\r
879                 ( portMPU_REGION_READ_WRITE ) | /* Read and write. */\r
880                 ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) |\r
881                 ( ( configTEX_S_C_B_SRAM & portMPU_RASR_TEX_S_C_B_MASK ) << portMPU_RASR_TEX_S_C_B_LOCATION ) |\r
882                 ( portMPU_REGION_ENABLE );\r
883         }\r
884 \r
885         lIndex = 0;\r
886 \r
887         for( ul = 1; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )\r
888         {\r
889             if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )\r
890             {\r
891                 /* Translate the generic region definition contained in\r
892                  * xRegions into the CM4 specific MPU settings that are then\r
893                  * stored in xMPUSettings. */\r
894                 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =\r
895                     ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |\r
896                     ( portMPU_REGION_VALID ) |\r
897                     ( portSTACK_REGION + ul ); /* Region number. */\r
898 \r
899                 xMPUSettings->xRegion[ ul ].ulRegionAttribute =\r
900                     ( prvGetMPURegionSizeSetting( xRegions[ lIndex ].ulLengthInBytes ) ) |\r
901                     ( xRegions[ lIndex ].ulParameters ) |\r
902                     ( portMPU_REGION_ENABLE );\r
903             }\r
904             else\r
905             {\r
906                 /* Invalidate the region. */\r
907                 xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;\r
908                 xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;\r
909             }\r
910 \r
911             lIndex++;\r
912         }\r
913     }\r
914 }\r
915 /*-----------------------------------------------------------*/\r
916 \r
917 #if ( configASSERT_DEFINED == 1 )\r
918 \r
919     void vPortValidateInterruptPriority( void )\r
920     {\r
921         uint32_t ulCurrentInterrupt;\r
922         uint8_t ucCurrentPriority;\r
923 \r
924         /* Obtain the number of the currently executing interrupt. */\r
925         __asm volatile ( "mrs %0, ipsr" : "=r" ( ulCurrentInterrupt )::"memory" );\r
926 \r
927         /* Is the interrupt number a user defined interrupt? */\r
928         if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )\r
929         {\r
930             /* Look up the interrupt's priority. */\r
931             ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];\r
932 \r
933             /* The following assertion will fail if a service routine (ISR) for\r
934              * an interrupt that has been assigned a priority above\r
935              * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API\r
936              * function.  ISR safe FreeRTOS API functions must *only* be called\r
937              * from interrupts that have been assigned a priority at or below\r
938              * configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
939              *\r
940              * Numerically low interrupt priority numbers represent logically high\r
941              * interrupt priorities, therefore the priority of the interrupt must\r
942              * be set to a value equal to or numerically *higher* than\r
943              * configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
944              *\r
945              * Interrupts that use the FreeRTOS API must not be left at their\r
946              * default priority of zero as that is the highest possible priority,\r
947              * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,\r
948              * and therefore also guaranteed to be invalid.\r
949              *\r
950              * FreeRTOS maintains separate thread and ISR API functions to ensure\r
951              * interrupt entry is as fast and simple as possible.\r
952              *\r
953              * The following links provide detailed information:\r
954              * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html\r
955              * https://www.FreeRTOS.org/FAQHelp.html */\r
956             configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );\r
957         }\r
958 \r
959         /* Priority grouping:  The interrupt controller (NVIC) allows the bits\r
960          * that define each interrupt's priority to be split between bits that\r
961          * define the interrupt's pre-emption priority bits and bits that define\r
962          * the interrupt's sub-priority.  For simplicity all bits must be defined\r
963          * to be pre-emption priority bits.  The following assertion will fail if\r
964          * this is not the case (if some bits represent a sub-priority).\r
965          *\r
966          * If the application only uses CMSIS libraries for interrupt\r
967          * configuration then the correct setting can be achieved on all Cortex-M\r
968          * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the\r
969          * scheduler.  Note however that some vendor specific peripheral libraries\r
970          * assume a non-zero priority group setting, in which cases using a value\r
971          * of zero will result in unpredicable behaviour. */\r
972         configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );\r
973     }\r
974 \r
975 #endif /* configASSERT_DEFINED */\r
976 /*-----------------------------------------------------------*/\r