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