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