]> begriffs open source - freertos/blob - portable/GCC/ARM_CRx_No_GIC/portASM.S
FreeRTOS MPU: Remove MPU region number check (#1261)
[freertos] / portable / GCC / ARM_CRx_No_GIC / portASM.S
1 /*
2  * FreeRTOS Kernel <DEVELOPMENT BRANCH>
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28
29     .text
30     .arm
31     .syntax unified
32
33     .set SYS_MODE,   0x1f
34     .set SVC_MODE,   0x13
35     .set IRQ_MODE,   0x12
36     .set CPSR_I_BIT, 0x80
37
38     /* Variables and functions. */
39     .extern pxCurrentTCB
40     .extern vTaskSwitchContext
41     .extern vApplicationIRQHandler
42     .extern vApplicationFPUSafeIRQHandler
43     .extern ulPortInterruptNesting
44     .extern ulPortTaskHasFPUContext
45     .extern ulICCEOIR
46     .extern ulPortYieldRequired
47
48     .global FreeRTOS_IRQ_Handler
49     .global FreeRTOS_SVC_Handler
50     .global vPortRestoreTaskContext
51     .global vPortInitialiseFPSCR
52     .global ulReadAPSR
53     .global vPortYield
54     .global vPortEnableInterrupts
55     .global vPortDisableInterrupts
56     .global ulPortSetInterruptMaskFromISR
57     .global ulPortCountLeadingZeros
58
59     .weak   vApplicationSVCHandler
60 /*-----------------------------------------------------------*/
61
62 .macro portSAVE_CONTEXT
63
64     /* Save the LR and SPSR onto the system mode stack before switching to
65      * system mode to save the remaining system mode registers. */
66     SRSDB   SP!, #SYS_MODE
67     CPS     #SYS_MODE
68     PUSH    {R0-R12, R14}
69
70     /* Push the critical nesting count. */
71     LDR     R2, =ulCriticalNesting
72     LDR     R1, [R2]
73     PUSH    {R1}
74
75     /* Does the task have a floating point context that needs saving?  If
76      * ulPortTaskHasFPUContext is 0 then no. */
77     LDR     R2, =ulPortTaskHasFPUContext
78     LDR     R3, [R2]
79     CMP     R3, #0
80
81     /* Save the floating point context, if any. */
82     VMRSNE  R1,  FPSCR
83     VPUSHNE {D0-D15}
84 #if configFPU_D32 == 1
85     VPUSHNE {D16-D31}
86 #endif /* configFPU_D32 */
87     PUSHNE  {R1}
88
89     /* Save ulPortTaskHasFPUContext itself. */
90     PUSH    {R3}
91
92     /* Save the stack pointer in the TCB. */
93     LDR     R0, =pxCurrentTCB
94     LDR     R1, [R0]
95     STR     SP, [R1]
96
97     .endm
98
99 /*-----------------------------------------------------------*/
100
101 .macro portRESTORE_CONTEXT
102
103     /* Set the SP to point to the stack of the task being restored. */
104     LDR     R0, =pxCurrentTCB
105     LDR     R1, [R0]
106     LDR     SP, [R1]
107
108     /* Is there a floating point context to restore?  If the restored
109      * ulPortTaskHasFPUContext is zero then no. */
110     LDR     R0, =ulPortTaskHasFPUContext
111     POP     {R1}
112     STR     R1, [R0]
113     CMP     R1, #0
114
115     /* Restore the floating point context, if any. */
116     POPNE   {R0}
117 #if configFPU_D32 == 1
118     VPOPNE  {D16-D31}
119 #endif /* configFPU_D32 */
120     VPOPNE  {D0-D15}
121     VMSRNE  FPSCR, R0
122
123     /* Restore the critical section nesting depth. */
124     LDR     R0, =ulCriticalNesting
125     POP     {R1}
126     STR     R1, [R0]
127
128     /* Restore all system mode registers other than the SP (which is already
129     being used). */
130     POP     {R0-R12, R14}
131
132     /* Return to the task code, loading CPSR on the way. */
133     RFEIA   SP!
134
135     .endm
136
137 /*-----------------------------------------------------------*/
138
139 /*
140  * void vPortRestoreTaskContext( void );
141  *
142  * vPortRestoreTaskContext is used to start the scheduler.
143  */
144 .align 4
145 .type vPortRestoreTaskContext, %function
146 vPortRestoreTaskContext:
147     /* Switch to system mode. */
148     CPS     #SYS_MODE
149     portRESTORE_CONTEXT
150
151 /*-----------------------------------------------------------*/
152
153 /*
154  * void vPortInitialiseFPSCR( void );
155  *
156  * vPortInitialiseFPSCR is used to initialize the FPSCR register.
157  */
158 .align 4
159 .type vPortInitialiseFPSCR, %function
160 vPortInitialiseFPSCR:
161     MOV     R0, #0
162     VMSR    FPSCR, R0
163     BX      LR
164
165 /*-----------------------------------------------------------*/
166
167 /*
168  * uint32_t ulReadAPSR( void );
169  *
170  * ulReadAPSR is used to read the value of APSR context.
171  */
172 .align 4
173 .type ulReadAPSR, %function
174 ulReadAPSR:
175     MRS R0, APSR
176     BX  LR
177
178 /*-----------------------------------------------------------*/
179
180 /*
181  * void vPortYield( void );
182  */
183 .align 4
184 .type vPortYield, %function
185 vPortYield:
186     SVC 0
187     ISB
188     BX  LR
189
190 /*-----------------------------------------------------------*/
191
192 /*
193  * void vPortEnableInterrupts( void );
194  */
195 .align 4
196 .type vPortEnableInterrupts, %function
197 vPortEnableInterrupts:
198     CPSIE   I
199     BX      LR
200
201 /*-----------------------------------------------------------*/
202
203 /*
204  * void vPortDisableInterrupts( void );
205  */
206 .align 4
207 .type vPortDisableInterrupts, %function
208 vPortDisableInterrupts:
209     CPSID    I
210     DSB
211     ISB
212     BX      LR
213
214 /*-----------------------------------------------------------*/
215
216 /*
217  * uint32_t ulPortSetInterruptMaskFromISR( void );
218  */
219 .align 4
220 .type ulPortSetInterruptMaskFromISR, %function
221 ulPortSetInterruptMaskFromISR:
222     MRS     R0, CPSR
223     AND     R0, R0, #CPSR_I_BIT
224     CPSID   I
225     DSB
226     ISB
227     BX      LR
228
229 /*-----------------------------------------------------------*/
230
231 /*
232  * void vApplicationSVCHandler( uint32_t ulSvcNumber );
233  */
234 .align 4
235 .type vApplicationSVCHandler, %function
236 vApplicationSVCHandler:
237     B vApplicationSVCHandler
238
239 /*-----------------------------------------------------------*/
240
241 /* If the application provides an implementation of vApplicationIRQHandler(),
242  * then it will get called directly without saving the FPU registers on
243  * interrupt entry, and this weak implementation of vApplicationIRQHandler()
244  * will not get called.
245  *
246  * If the application provides its own implementation of
247  * vApplicationFPUSafeIRQHandler() then this implementation of
248  * vApplicationIRQHandler() will be called, save the FPU registers, and then
249  * call vApplicationFPUSafeIRQHandler().
250  *
251  * Therefore, if the application writer wants FPU registers to be saved on
252  * interrupt entry, their IRQ handler must be called
253  * vApplicationFPUSafeIRQHandler(), and if the application writer does not want
254  * FPU registers to be saved on interrupt entry their IRQ handler must be
255  * called vApplicationIRQHandler().
256  */
257 .align 4
258 .weak vApplicationIRQHandler
259 .type vApplicationIRQHandler, %function
260 vApplicationIRQHandler:
261     PUSH    {LR}
262
263     VMRS    R1, FPSCR
264     VPUSH   {D0-D7}
265     PUSH    {R1}
266
267     BLX     vApplicationFPUSafeIRQHandler
268
269     POP     {R0}
270     VPOP    {D0-D7}
271     VMSR    FPSCR, R0
272
273     POP     {PC}
274
275 /*-----------------------------------------------------------*/
276
277 .align 4
278 .weak vApplicationFPUSafeIRQHandler
279 .type vApplicationFPUSafeIRQHandler, %function
280 vApplicationFPUSafeIRQHandler:
281     B       vApplicationFPUSafeIRQHandler
282
283 /*-----------------------------------------------------------*/
284
285 /*
286  * UBaseType_t ulPortCountLeadingZeros( UBaseType_t ulBitmap );
287  *
288  * According to the Procedure Call Standard for the ARM Architecture (AAPCS):
289  * - Parameter ulBitmap is passed in R0.
290  * - Return value must be in R0.
291  */
292 .align 4
293 .type ulPortCountLeadingZeros, %function
294 ulPortCountLeadingZeros:
295     CLZ     R0, R0
296     BX      LR
297
298 /*-----------------------------------------------------------*/
299
300 /*
301  * SVC handler is used to yield.
302  */
303 .align 4
304 .type FreeRTOS_SVC_Handler, %function
305 FreeRTOS_SVC_Handler:
306     PUSH    { R0-R1 }
307
308     /* ---------------------------- Get Caller SVC Number ---------------------------- */
309     MRS     R0, SPSR               /* R0 = CPSR at the time of SVC. */
310     TST     R0, #0x20              /* Check Thumb bit (5) in CPSR. */
311     LDRHNE  R0, [LR, #-0x2]        /* If Thumb, load halfword. */
312     BICNE   R0, R0, #0xFF00        /* And extract immidiate field (i.e. SVC number). */
313     LDREQ   R0, [LR, #-0x4]        /* If ARM, load word. */
314     BICEQ   R0, R0, #0xFF000000    /* And extract immidiate field (i.e. SVC number). */
315
316     /* --------------------------------- SVC Routing --------------------------------- */
317     CMP     R0, #0
318     BEQ     svcPortYield
319     BNE     svcApplicationCall
320
321 svcPortYield:
322     POP     { R0-R1 }
323     portSAVE_CONTEXT
324     BLX     vTaskSwitchContext
325     portRESTORE_CONTEXT
326
327 svcApplicationCall:
328     POP     { R0-R1 }
329     portSAVE_CONTEXT
330     BLX     vApplicationSVCHandler
331     portRESTORE_CONTEXT
332
333 /*-----------------------------------------------------------*/
334
335 .align 4
336 .type FreeRTOS_IRQ_Handler, %function
337 FreeRTOS_IRQ_Handler:
338     /* Return to the interrupted instruction. */
339     SUB     LR, LR, #4
340
341     /* Push the return address and SPSR. */
342     PUSH    {LR}
343     MRS     LR, SPSR
344     PUSH    {LR}
345
346     /* Change to supervisor mode to allow reentry. */
347     CPS     #SVC_MODE
348
349     /* Push used registers. */
350     PUSH    {R0-R3, R12}
351
352     /* Increment nesting count.  r3 holds the address of ulPortInterruptNesting
353      * for future use.  r1 holds the original ulPortInterruptNesting value for
354      * future use. */
355     LDR     R3, =ulPortInterruptNesting
356     LDR     R1, [R3]
357     ADD     R0, R1, #1
358     STR     R0, [R3]
359
360     /* Ensure bit 2 of the stack pointer is clear.  r2 holds the bit 2 value for
361      * future use. */
362     MOV     R0, SP
363     AND     R2, R0, #4
364     SUB     SP, SP, R2
365
366     /* Call the interrupt handler. */
367     PUSH    {R0-R3, LR}
368     BLX     vApplicationIRQHandler
369     POP     {R0-R3, LR}
370     ADD     SP, SP, R2
371
372     /* Disable IRQs incase vApplicationIRQHandler enabled them for re-entry. */
373     CPSID   i
374     DSB
375     ISB
376
377     /* Write to the EOI register. */
378     LDR     R0, =ulICCEOIR
379     LDR     R2, [R0]
380     STR     R0, [R2]
381
382     /* Restore the old nesting count. */
383     STR     R1, [R3]
384
385     /* A context switch is never performed if the nesting count is not 0. */
386     CMP     R1, #0
387     BNE     exit_without_switch
388
389     /* Did the interrupt request a context switch?  r1 holds the address of
390      * ulPortYieldRequired and r0 the value of ulPortYieldRequired for future
391      * use. */
392     LDR     R1, =ulPortYieldRequired
393     LDR     R0, [R1]
394     CMP     R0, #0
395     BNE     switch_before_exit
396
397 exit_without_switch:
398     /* No context switch.  Restore used registers, LR_irq and SPSR before
399      * returning. */
400     POP     {R0-R3, R12}
401     CPS     #IRQ_MODE
402     POP     {LR}
403     MSR     SPSR_cxsf, LR
404     POP     {LR}
405     MOVS    PC, LR
406
407 switch_before_exit:
408     /* A context switch is to be performed.  Clear the context switch pending
409      * flag. */
410     MOV     R0, #0
411     STR     R0, [R1]
412
413     /* Restore used registers, LR-irq and SPSR before saving the context
414      * to the task stack. */
415     POP     {R0-R3, R12}
416     CPS     #IRQ_MODE
417     POP     {LR}
418     MSR     SPSR_cxsf, LR
419     POP     {LR}
420     portSAVE_CONTEXT
421
422     /* Call the function that selects the new task to execute.
423      * vTaskSwitchContext() if vTaskSwitchContext() uses LDRD or STRD
424      * instructions, or 8 byte aligned stack allocated data.  LR does not need
425      * saving as a new LR will be loaded by portRESTORE_CONTEXT anyway. */
426     BLX     vTaskSwitchContext
427
428     /* Restore the context of, and branch to, the task selected to execute
429      * next. */
430     portRESTORE_CONTEXT
431
432 /*-----------------------------------------------------------*/
433
434 .end