]> begriffs open source - freertos/blob - portable/IAR/ARM_CM4F_MPU/portasm.s
Add Cortex M7 r0p1 Errata 837070 workaround to CM4_MPU ports (#513)
[freertos] / portable / IAR / ARM_CM4F_MPU / portasm.s
1 /*\r
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>\r
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * SPDX-License-Identifier: MIT\r
6  *\r
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
8  * this software and associated documentation files (the "Software"), to deal in\r
9  * the Software without restriction, including without limitation the rights to\r
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
11  * the Software, and to permit persons to whom the Software is furnished to do so,\r
12  * subject to the following conditions:\r
13  *\r
14  * The above copyright notice and this permission notice shall be included in all\r
15  * copies or substantial portions of the Software.\r
16  *\r
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
23  *\r
24  * https://www.FreeRTOS.org\r
25  * https://github.com/FreeRTOS\r
26  *\r
27  */\r
28 /* Including FreeRTOSConfig.h here will cause build errors if the header file\r
29 contains code not understood by the assembler - for example the 'extern' keyword.\r
30 To avoid errors place any such code inside a #ifdef __ICCARM__/#endif block so\r
31 the code is included in C files but excluded by the preprocessor in assembly\r
32 files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler. */\r
33 #include <FreeRTOSConfig.h>\r
34 \r
35         RSEG    CODE:CODE(2)\r
36         thumb\r
37 \r
38         EXTERN pxCurrentTCB\r
39         EXTERN vTaskSwitchContext\r
40         EXTERN vPortSVCHandler_C\r
41 \r
42         PUBLIC xPortPendSVHandler\r
43         PUBLIC vPortSVCHandler\r
44         PUBLIC vPortStartFirstTask\r
45         PUBLIC vPortEnableVFP\r
46         PUBLIC vPortRestoreContextOfFirstTask\r
47         PUBLIC xIsPrivileged\r
48         PUBLIC vResetPrivilege\r
49 \r
50 /*-----------------------------------------------------------*/\r
51 \r
52 xPortPendSVHandler:\r
53         mrs r0, psp\r
54         isb\r
55         /* Get the location of the current TCB. */\r
56         ldr     r3, =pxCurrentTCB\r
57         ldr     r2, [r3]\r
58 \r
59         /* Is the task using the FPU context?  If so, push high vfp registers. */\r
60         tst r14, #0x10\r
61         it eq\r
62         vstmdbeq r0!, {s16-s31}\r
63 \r
64         /* Save the core registers. */\r
65         mrs r1, control\r
66         stmdb r0!, {r1, r4-r11, r14}\r
67 \r
68         /* Save the new top of stack into the first member of the TCB. */\r
69         str r0, [r2]\r
70 \r
71         stmdb sp!, {r0, r3}\r
72         mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY\r
73         #if ( configENABLE_ERRATA_837070_WORKAROUND == 1 )\r
74                 cpsid i /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */\r
75         #endif\r
76         msr basepri, r0\r
77         dsb\r
78         isb\r
79         #if ( configENABLE_ERRATA_837070_WORKAROUND == 1 )\r
80                 cpsie i /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */\r
81         #endif\r
82         bl vTaskSwitchContext\r
83         mov r0, #0\r
84         msr basepri, r0\r
85         ldmia sp!, {r0, r3}\r
86 \r
87         /* The first item in pxCurrentTCB is the task top of stack. */\r
88         ldr r1, [r3]\r
89         ldr r0, [r1]\r
90         /* Move onto the second item in the TCB... */\r
91         add r1, r1, #4\r
92 \r
93         dmb                                     /* Complete outstanding transfers before disabling MPU. */\r
94         ldr r2, =0xe000ed94     /* MPU_CTRL register. */\r
95         ldr r3, [r2]            /* Read the value of MPU_CTRL. */\r
96         bic r3, r3, #1          /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */\r
97         str r3, [r2]            /* Disable MPU. */\r
98 \r
99         /* Region Base Address register. */\r
100         ldr r2, =0xe000ed9c\r
101         /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
102         ldmia r1!, {r4-r11}\r
103         /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
104         stmia r2, {r4-r11}\r
105 \r
106         #ifdef configTOTAL_MPU_REGIONS\r
107                 #if ( configTOTAL_MPU_REGIONS == 16 )\r
108                         /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */\r
109                         ldmia r1!, {r4-r11}\r
110                         /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */\r
111                         stmia r2, {r4-r11}\r
112                         /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */\r
113                         ldmia r1!, {r4-r11}\r
114                         /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */\r
115                         stmia r2, {r4-r11}\r
116                 #endif /* configTOTAL_MPU_REGIONS == 16. */\r
117         #endif /* configTOTAL_MPU_REGIONS */\r
118 \r
119         ldr r2, =0xe000ed94     /* MPU_CTRL register. */\r
120         ldr r3, [r2]            /* Read the value of MPU_CTRL. */\r
121         orr r3, r3, #1          /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */\r
122         str r3, [r2]            /* Enable MPU. */\r
123         dsb                                     /* Force memory writes before continuing. */\r
124 \r
125         /* Pop the registers that are not automatically saved on exception entry. */\r
126         ldmia r0!, {r3-r11, r14}\r
127         msr control, r3\r
128 \r
129         /* Is the task using the FPU context?  If so, pop the high vfp registers\r
130         too. */\r
131         tst r14, #0x10\r
132         it eq\r
133         vldmiaeq r0!, {s16-s31}\r
134 \r
135         msr psp, r0\r
136         isb\r
137 \r
138         bx r14\r
139 \r
140 \r
141 /*-----------------------------------------------------------*/\r
142 \r
143 vPortSVCHandler:\r
144         #ifndef USE_PROCESS_STACK       /* Code should not be required if a main() is using the process stack. */\r
145                 tst lr, #4\r
146                 ite eq\r
147                 mrseq r0, msp\r
148                 mrsne r0, psp\r
149         #else\r
150                 mrs r0, psp\r
151         #endif\r
152                 b vPortSVCHandler_C\r
153 \r
154 /*-----------------------------------------------------------*/\r
155 \r
156 vPortStartFirstTask:\r
157         /* Use the NVIC offset register to locate the stack. */\r
158         ldr r0, =0xE000ED08\r
159         ldr r0, [r0]\r
160         ldr r0, [r0]\r
161         /* Set the msp back to the start of the stack. */\r
162         msr msp, r0\r
163         /* Clear the bit that indicates the FPU is in use in case the FPU was used\r
164         before the scheduler was started - which would otherwise result in the\r
165         unnecessary leaving of space in the SVC stack for lazy saving of FPU\r
166         registers. */\r
167         mov r0, #0\r
168         msr control, r0\r
169         /* Call SVC to start the first task. */\r
170         cpsie i\r
171         cpsie f\r
172         dsb\r
173         isb\r
174         svc 0\r
175 \r
176 /*-----------------------------------------------------------*/\r
177 \r
178 vPortRestoreContextOfFirstTask:\r
179         /* Use the NVIC offset register to locate the stack. */\r
180         ldr r0, =0xE000ED08\r
181         ldr r0, [r0]\r
182         ldr r0, [r0]\r
183         /* Set the msp back to the start of the stack. */\r
184         msr msp, r0\r
185         /* Restore the context. */\r
186         ldr     r3, =pxCurrentTCB\r
187         ldr r1, [r3]\r
188         /* The first item in the TCB is the task top of stack. */\r
189         ldr r0, [r1]\r
190         /* Move onto the second item in the TCB... */\r
191         add r1, r1, #4\r
192 \r
193         dmb                                     /* Complete outstanding transfers before disabling MPU. */\r
194         ldr r2, =0xe000ed94     /* MPU_CTRL register. */\r
195         ldr r3, [r2]            /* Read the value of MPU_CTRL. */\r
196         bic r3, r3, #1          /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */\r
197         str r3, [r2]            /* Disable MPU. */\r
198 \r
199         /* Region Base Address register. */\r
200         ldr r2, =0xe000ed9c\r
201         /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
202         ldmia r1!, {r4-r11}\r
203         /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */\r
204         stmia r2, {r4-r11}\r
205 \r
206         #ifdef configTOTAL_MPU_REGIONS\r
207                 #if ( configTOTAL_MPU_REGIONS == 16 )\r
208                         /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */\r
209                         ldmia r1!, {r4-r11}\r
210                         /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */\r
211                         stmia r2, {r4-r11}\r
212                         /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */\r
213                         ldmia r1!, {r4-r11}\r
214                         /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */\r
215                         stmia r2, {r4-r11}\r
216                 #endif /* configTOTAL_MPU_REGIONS == 16. */\r
217         #endif /* configTOTAL_MPU_REGIONS */\r
218 \r
219         ldr r2, =0xe000ed94     /* MPU_CTRL register. */\r
220         ldr r3, [r2]            /* Read the value of MPU_CTRL. */\r
221         orr r3, r3, #1          /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */\r
222         str r3, [r2]            /* Enable MPU. */\r
223         dsb                                     /* Force memory writes before continuing. */\r
224 \r
225         /* Pop the registers that are not automatically saved on exception entry. */\r
226         ldmia r0!, {r3-r11, r14}\r
227         msr control, r3\r
228         /* Restore the task stack pointer. */\r
229         msr psp, r0\r
230         mov r0, #0\r
231         msr     basepri, r0\r
232         bx r14\r
233 \r
234 /*-----------------------------------------------------------*/\r
235 \r
236 vPortEnableVFP:\r
237         /* The FPU enable bits are in the CPACR. */\r
238         ldr.w r0, =0xE000ED88\r
239         ldr     r1, [r0]\r
240 \r
241         /* Enable CP10 and CP11 coprocessors, then save back. */\r
242         orr     r1, r1, #( 0xf << 20 )\r
243         str r1, [r0]\r
244         bx      r14\r
245 \r
246 /*-----------------------------------------------------------*/\r
247 \r
248 xIsPrivileged:\r
249         mrs r0, control         /* r0 = CONTROL. */\r
250         tst r0, #1                      /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */\r
251         ite ne\r
252         movne r0, #0            /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */\r
253         moveq r0, #1            /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */\r
254         bx lr                           /* Return. */\r
255 /*-----------------------------------------------------------*/\r
256 \r
257 vResetPrivilege:\r
258         mrs r0, control         /* r0 = CONTROL. */\r
259         orr r0, r0, #1          /* r0 = r0 | 1. */\r
260         msr control, r0         /* CONTROL = r0. */\r
261         bx lr                           /* Return to the caller. */\r
262 /*-----------------------------------------------------------*/\r
263 \r
264         END\r