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