xref: /Kernel-v10.6.2/portable/IAR/ARM_CM4F_MPU/portasm.s (revision ef7b253b56c9788077f5ecd6c9deb4021923d646)
1/*
2 * FreeRTOS Kernel V10.6.2
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/* Including FreeRTOSConfig.h here will cause build errors if the header file
30contains code not understood by the assembler - for example the 'extern' keyword.
31To avoid errors place any such code inside a #ifdef __ICCARM__/#endif block so
32the code is included in C files but excluded by the preprocessor in assembly
33files (__ICCARM__ is defined by the IAR C compiler but not by the IAR assembler. */
34#include <FreeRTOSConfig.h>
35#include <mpu_syscall_numbers.h>
36
37    RSEG    CODE:CODE(2)
38    thumb
39
40    EXTERN pxCurrentTCB
41    EXTERN vTaskSwitchContext
42    EXTERN vPortSVCHandler_C
43    EXTERN vSystemCallEnter
44    EXTERN vSystemCallExit
45
46    PUBLIC xPortPendSVHandler
47    PUBLIC vPortSVCHandler
48    PUBLIC vPortStartFirstTask
49    PUBLIC vPortEnableVFP
50    PUBLIC vPortRestoreContextOfFirstTask
51    PUBLIC xIsPrivileged
52    PUBLIC vResetPrivilege
53
54/*-----------------------------------------------------------*/
55
56#ifndef configUSE_MPU_WRAPPERS_V1
57    #define configUSE_MPU_WRAPPERS_V1 0
58#endif
59
60/* These must be in sync with portmacro.h. */
61#define portSVC_START_SCHEDULER        100
62#define portSVC_SYSTEM_CALL_EXIT       103
63/*-----------------------------------------------------------*/
64
65xPortPendSVHandler:
66
67    ldr r3, =pxCurrentTCB
68    ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
69    ldr r1, [r2]                           /* r1 = Location where the context should be saved. */
70
71    /*------------ Save Context. ----------- */
72    mrs r3, control
73    mrs r0, psp
74    isb
75
76    add r0, r0, #0x20                      /* Move r0 to location where s0 is saved. */
77    tst lr, #0x10
78    ittt eq
79    vstmiaeq r1!, {s16-s31}                /* Store s16-s31. */
80    vldmiaeq r0, {s0-s16}                  /* Copy hardware saved FP context into s0-s16. */
81    vstmiaeq r1!, {s0-s16}                 /* Store hardware saved FP context. */
82    sub r0, r0, #0x20                      /* Set r0 back to the location of hardware saved context. */
83
84    stmia r1!, {r3-r11, lr}                /* Store CONTROL register, r4-r11 and LR. */
85    ldmia r0, {r4-r11}                     /* Copy hardware saved context into r4-r11. */
86    stmia r1!, {r0, r4-r11}                /* Store original PSP (after hardware has saved context) and the hardware saved context. */
87    str r1, [r2]                           /* Save the location from where the context should be restored as the first member of TCB. */
88
89    /*---------- Select next task. --------- */
90    mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
91#if ( configENABLE_ERRATA_837070_WORKAROUND == 1 )
92    cpsid i                                /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */
93#endif
94    msr basepri, r0
95    dsb
96    isb
97#if ( configENABLE_ERRATA_837070_WORKAROUND == 1 )
98    cpsie i                                /* ARM Cortex-M7 r0p1 Errata 837070 workaround. */
99#endif
100    bl vTaskSwitchContext
101    mov r0, #0
102    msr basepri, r0
103
104    /*------------ Program MPU. ------------ */
105    ldr r3, =pxCurrentTCB
106    ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
107    add r2, r2, #4                         /* r2 = Second item in the TCB which is xMPUSettings. */
108
109    dmb                                    /* Complete outstanding transfers before disabling MPU. */
110    ldr r0, =0xe000ed94                    /* MPU_CTRL register. */
111    ldr r3, [r0]                           /* Read the value of MPU_CTRL. */
112    bic r3, #1                             /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
113    str r3, [r0]                           /* Disable MPU. */
114
115    ldr r0, =0xe000ed9c                    /* Region Base Address register. */
116    ldmia r2!, {r4-r11}                    /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */
117    stmia r0, {r4-r11}                     /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */
118
119#ifdef configTOTAL_MPU_REGIONS
120    #if ( configTOTAL_MPU_REGIONS == 16 )
121        ldmia r2!, {r4-r11}                 /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */
122        stmia r0, {r4-r11}                  /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */
123        ldmia r2!, {r4-r11}                 /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */
124        stmia r0, {r4-r11}                  /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */
125    #endif /* configTOTAL_MPU_REGIONS == 16. */
126#endif
127
128    ldr r0, =0xe000ed94                    /* MPU_CTRL register. */
129    ldr r3, [r0]                           /* Read the value of MPU_CTRL. */
130    orr r3, #1                             /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
131    str r3, [r0]                           /* Enable MPU. */
132    dsb                                    /* Force memory writes before continuing. */
133
134    /*---------- Restore Context. ---------- */
135    ldr r3, =pxCurrentTCB
136    ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
137    ldr r1, [r2]                           /* r1 = Location of saved context in TCB. */
138
139    ldmdb r1!, {r0, r4-r11}                /* r0 contains PSP after the hardware had saved context. r4-r11 contain hardware saved context. */
140    msr psp, r0
141    stmia r0!, {r4-r11}                    /* Copy the hardware saved context on the task stack. */
142    ldmdb r1!, {r3-r11, lr}                /* r3 contains CONTROL register. r4-r11 and LR restored. */
143    msr control, r3
144
145    tst lr, #0x10
146    ittt eq
147    vldmdbeq r1!, {s0-s16}                 /* s0-s16 contain hardware saved FP context. */
148    vstmiaeq r0!, {s0-s16}                 /* Copy hardware saved FP context on the task stack. */
149    vldmdbeq r1!, {s16-s31}                /* Restore s16-s31. */
150
151    str r1, [r2]                           /* Save the location where the context should be saved next as the first member of TCB. */
152    bx lr
153
154/*-----------------------------------------------------------*/
155
156#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
157
158vPortSVCHandler:
159    tst lr, #4
160    ite eq
161    mrseq r0, msp
162    mrsne r0, psp
163
164    ldr r1, [r0, #24]
165    ldrb r2, [r1, #-2]
166    cmp r2, #NUM_SYSTEM_CALLS
167    blt syscall_enter
168    cmp r2, #portSVC_SYSTEM_CALL_EXIT
169    beq syscall_exit
170    b vPortSVCHandler_C
171
172    syscall_enter:
173        mov r1, lr
174        b vSystemCallEnter
175
176    syscall_exit:
177        mov r1, lr
178        b vSystemCallExit
179
180#else /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
181
182vPortSVCHandler:
183    #ifndef USE_PROCESS_STACK
184        tst lr, #4
185        ite eq
186        mrseq r0, msp
187        mrsne r0, psp
188    #else
189        mrs r0, psp
190    #endif
191        b vPortSVCHandler_C
192
193#endif /* #if ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
194/*-----------------------------------------------------------*/
195
196vPortStartFirstTask:
197    /* Use the NVIC offset register to locate the stack. */
198    ldr r0, =0xE000ED08
199    ldr r0, [r0]
200    ldr r0, [r0]
201    /* Set the msp back to the start of the stack. */
202    msr msp, r0
203    /* Clear the bit that indicates the FPU is in use in case the FPU was used
204    before the scheduler was started - which would otherwise result in the
205    unnecessary leaving of space in the SVC stack for lazy saving of FPU
206    registers. */
207    mov r0, #0
208    msr control, r0
209    /* Call SVC to start the first task. */
210    cpsie i
211    cpsie f
212    dsb
213    isb
214    svc #portSVC_START_SCHEDULER
215
216/*-----------------------------------------------------------*/
217
218vPortRestoreContextOfFirstTask:
219    ldr r0, =0xE000ED08                    /* Use the NVIC offset register to locate the stack. */
220    ldr r0, [r0]
221    ldr r0, [r0]
222    msr msp, r0                            /* Set the msp back to the start of the stack. */
223
224    /*------------ Program MPU. ------------ */
225    ldr r3, =pxCurrentTCB
226    ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
227    add r2, r2, #4                         /* r2 = Second item in the TCB which is xMPUSettings. */
228
229    dmb                                    /* Complete outstanding transfers before disabling MPU. */
230    ldr r0, =0xe000ed94                    /* MPU_CTRL register. */
231    ldr r3, [r0]                           /* Read the value of MPU_CTRL. */
232    bic r3, #1                             /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
233    str r3, [r0]                           /* Disable MPU. */
234
235    ldr r0, =0xe000ed9c                    /* Region Base Address register. */
236    ldmia r2!, {r4-r11}                    /* Read 4 sets of MPU registers [MPU Region # 4 - 7]. */
237    stmia r0, {r4-r11}                     /* Write 4 sets of MPU registers [MPU Region # 4 - 7]. */
238
239#ifdef configTOTAL_MPU_REGIONS
240    #if ( configTOTAL_MPU_REGIONS == 16 )
241        ldmia r2!, {r4-r11}                /* Read 4 sets of MPU registers [MPU Region # 8 - 11]. */
242        stmia r0, {r4-r11}                 /* Write 4 sets of MPU registers. [MPU Region # 8 - 11]. */
243        ldmia r2!, {r4-r11}                /* Read 4 sets of MPU registers [MPU Region # 12 - 15]. */
244        stmia r0, {r4-r11}                 /* Write 4 sets of MPU registers. [MPU Region # 12 - 15]. */
245    #endif /* configTOTAL_MPU_REGIONS == 16. */
246#endif
247
248    ldr r0, =0xe000ed94                    /* MPU_CTRL register. */
249    ldr r3, [r0]                           /* Read the value of MPU_CTRL. */
250    orr r3, #1                             /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
251    str r3, [r0]                           /* Enable MPU. */
252    dsb                                    /* Force memory writes before continuing. */
253
254    /*---------- Restore Context. ---------- */
255    ldr r3, =pxCurrentTCB
256    ldr r2, [r3]                           /* r2 = pxCurrentTCB. */
257    ldr r1, [r2]                           /* r1 = Location of saved context in TCB. */
258
259    ldmdb r1!, {r0, r4-r11}                /* r0 contains PSP after the hardware had saved context. r4-r11 contain hardware saved context. */
260    msr psp, r0
261    stmia r0, {r4-r11}                     /* Copy the hardware saved context on the task stack. */
262    ldmdb r1!, {r3-r11, lr}                /* r3 contains CONTROL register. r4-r11 and LR restored. */
263    msr control, r3
264    str r1, [r2]                           /* Save the location where the context should be saved next as the first member of TCB. */
265
266    mov r0, #0
267    msr basepri, r0
268    bx lr
269
270/*-----------------------------------------------------------*/
271
272vPortEnableVFP:
273    /* The FPU enable bits are in the CPACR. */
274    ldr.w r0, =0xE000ED88
275    ldr r1, [r0]
276
277    /* Enable CP10 and CP11 coprocessors, then save back. */
278    orr r1, r1, #( 0xf << 20 )
279    str r1, [r0]
280    bx  r14
281
282/*-----------------------------------------------------------*/
283
284xIsPrivileged:
285    mrs r0, control     /* r0 = CONTROL. */
286    tst r0, #1          /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */
287    ite ne
288    movne r0, #0        /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
289    moveq r0, #1        /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */
290    bx lr               /* Return. */
291/*-----------------------------------------------------------*/
292
293vResetPrivilege:
294    mrs r0, control     /* r0 = CONTROL. */
295    orr r0, r0, #1      /* r0 = r0 | 1. */
296    msr control, r0     /* CONTROL = r0. */
297    bx lr               /* Return to the caller. */
298/*-----------------------------------------------------------*/
299
300    END
301