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