summaryrefslogtreecommitdiff
path: root/tool/mbed/mbed-sdk/libraries/rtos/rtx/TARGET_CORTEX_A/TOOLCHAIN_GCC/HAL_CA9.s
blob: c0e9836c7e599bf36fe2ae2e0c09f28b6e380307 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
/*----------------------------------------------------------------------------
 *      RL-ARM - RTX
 *----------------------------------------------------------------------------
 *      Name:    HAL_CA9.c
 *      Purpose: Hardware Abstraction Layer for Cortex-A9
 *      Rev.:    3 Sept 2013
 *----------------------------------------------------------------------------
 *
 * Copyright (c) 2012 - 2013 ARM Limited
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *  - Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *  - Neither the name of ARM  nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *---------------------------------------------------------------------------*/

    .global rt_set_PSP
    .global rt_get_PSP
    .global _alloc_box
    .global _free_box
    .global PendSV_Handler
    .global OS_Tick_Handler

    .EQU CPSR_T_BIT,    0x20
    .EQU CPSR_I_BIT,    0x80
    .EQU CPSR_F_BIT,    0x40

    .EQU MODE_USR,      0x10
    .EQU MODE_FIQ,      0x11
    .EQU MODE_IRQ,      0x12
    .EQU MODE_SVC,      0x13
    .EQU MODE_ABT,      0x17
    .EQU MODE_UND,      0x1B
    .EQU MODE_SYS,      0x1F

    .EQU TCB_TID,        3        /* 'task id' offset                        */
    .EQU TCB_STACKF,    32        /* 'stack_frame' offset                    */
    .EQU TCB_TSTACK,    36        /* 'tsk_stack' offset                      */

    .extern rt_alloc_box
    .extern os_tsk
    .extern GICInterface_BASE
    .extern rt_pop_req
    .extern os_tick_irqack
    .extern rt_systick

/*----------------------------------------------------------------------------
 *      Functions
 *---------------------------------------------------------------------------*/
    .text
@ For A-class, set USR/SYS stack
@ __asm void rt_set_PSP (U32 stack) {
rt_set_PSP:
        .arm

        MRS     R1, CPSR
        CPS     #MODE_SYS   @no effect in USR mode
        ISB
        MOV     SP, R0
        MSR     CPSR_c, R1  @no effect in USR mode
        ISB
        BX      LR

@ }

@ For A-class, get USR/SYS stack
@ __asm U32 rt_get_PSP (void) {
rt_get_PSP:
        .arm

        MRS     R1, CPSR
        CPS     #MODE_SYS   @no effect in USR mode
        ISB
        MOV     R0, SP
        MSR     CPSR_c, R1  @no effect in USR mode
        ISB
        BX      LR

@ }

/*--------------------------- _alloc_box ------------------------------------*/
@ __asm void *_alloc_box (void *box_mem) {
_alloc_box:
    /* Function wrapper for Unprivileged/Privileged mode. */
        .arm

        LDR     R12,=rt_alloc_box       @ __cpp(rt_alloc_box)
        MRS     R2, CPSR
        LSLS    R2, #28
        BXNE    R12
        SVC     0
        BX      LR
@ }


/*--------------------------- _free_box -------------------------------------*/
@ __asm int _free_box (void *box_mem, void *box) {
_free_box:
   /* Function wrapper for Unprivileged/Privileged mode. */
        .arm

        LDR     R12,=rt_free_box        @ __cpp(rt_free_box)
        MRS     R2, CPSR
        LSLS    R2, #28
        BXNE    R12
        SVC     0
        BX      LR

@ }

/*-------------------------- SVC_Handler -----------------------------------*/

@ #pragma push
@ #pragma arm
@ __asm void SVC_Handler (void) {

        .type   SVC_Handler, %function
        .global SVC_Handler
SVC_Handler:
@         PRESERVE8
        .arm
        .extern  rt_tsk_lock
        .extern  rt_tsk_unlock
        .extern  SVC_Count
        .extern  SVC_Table
        .extern  rt_stk_check
        .extern  FPUEnable

        .EQU    Mode_SVC, 0x13

        SRSDB   SP!, #Mode_SVC         @ Push LR_SVC and SPRS_SVC onto SVC mode stack
        PUSH    {R4}                   @ Push R4 so we can use it as a temp


        MRS     R4,SPSR                @ Get SPSR
        TST     R4,#CPSR_T_BIT         @ Check Thumb Bit
        LDRNEH  R4,[LR,#-2]            @ Thumb: Load Halfword
        BICNE   R4,R4,#0xFF00          @        Extract SVC Number
        LDREQ   R4,[LR,#-4]            @ ARM:   Load Word
        BICEQ   R4,R4,#0xFF000000      @        Extract SVC Number

        /* Lock out systick and re-enable interrupts */
        PUSH    {R0-R3,R12,LR}

        AND     R12, SP, #4            @ Ensure stack is 8-byte aligned
        SUB     SP, SP, R12            @ Adjust stack
        PUSH    {R12, LR}              @ Store stack adjustment and dummy LR to SVC stack

        BLX     rt_tsk_lock
        CPSIE   i

        POP     {R12, LR}              @ Get stack adjustment & discard dummy LR
        ADD     SP, SP, R12            @ Unadjust stack

        POP     {R0-R3,R12,LR}

        CMP     R4,#0
        BNE     SVC_User

        MRS     R4,SPSR
        PUSH    {R4}                    @ Push R4 so we can use it as a temp
        AND     R4, SP, #4              @ Ensure stack is 8-byte aligned
        SUB     SP, SP, R4              @ Adjust stack
        PUSH    {R4, LR}                @ Store stack adjustment and dummy LR
        BLX     R12
        POP     {R4, LR}                @ Get stack adjustment & discard dummy LR
        ADD     SP, SP, R4              @ Unadjust stack
        POP     {R4}                    @ Restore R4
        MSR     SPSR_cxsf,R4

        /* Here we will be in SVC mode (even if coming in from PendSV_Handler or OS_Tick_Handler) */
Sys_Switch:
        LDR     LR,=os_tsk              @ __cpp(&os_tsk)
        LDM     LR,{R4,LR}              @ os_tsk.run, os_tsk.new
        CMP     R4,LR
        BNE     switching

        PUSH    {R0-R3,R12,LR}

        AND     R12, SP, #4             @ Ensure stack is 8-byte aligned
        SUB     SP, SP, R12             @ Adjust stack
        PUSH    {R12, LR}               @ Store stack adjustment and dummy LR to SVC stack

        CPSID   i
        BLX     rt_tsk_unlock

        POP     {R12, LR}               @ Get stack adjustment & discard dummy LR
        ADD     SP, SP, R12             @ Unadjust stack

        POP     {R0-R3,R12,LR}
        POP     {R4}
        RFEFD   SP!                     @ Return from exception, no task switch

switching:
        CLREX
        CMP     R4,#0
        ADDEQ   SP,SP,#12               @ Original R4, LR & SPSR do not need to be popped when we are paging in a different task
        BEQ     SVC_Next                @ Runtask deleted?


        PUSH    {R8-R11} @ R4 and LR already stacked
        MOV     R10,R4                  @ Preserve os_tsk.run
        MOV     R11,LR                  @ Preserve os_tsk.new

        ADD     R8,SP,#16               @ Unstack R4,LR
        LDMIA   R8,{R4,LR}

        SUB     SP,SP,#4                @ Make space on the stack for the next instn
        STMIA   SP,{SP}^                @ Put User SP onto stack
        POP     {R8}                    @ Pop User SP into R8

        MRS     R9,SPSR
        STMDB   R8!,{R9}                @ User CPSR
        STMDB   R8!,{LR}                @ User PC
        STMDB   R8,{LR}^                @ User LR
        SUB     R8,R8,#4                @ No writeback for store of User LR
        STMDB   R8!,{R0-R3,R12}         @ User R0-R3,R12
        MOV     R3,R10                  @ os_tsk.run
        MOV     LR,R11                  @ os_tsk.new
        POP     {R9-R12}
        ADD     SP,SP,#12               @ Fix up SP for unstack of R4, LR & SPSR
        STMDB   R8!,{R4-R7,R9-R12}      @ User R4-R11

        @ If applicable, stack VFP state
        MRC     p15,0,R1,c1,c0,2        @ VFP/NEON access enabled? (CPACR)
        AND     R2,R1,#0x00F00000
        CMP     R2,#0x00F00000
        BNE     no_outgoing_vfp
        VMRS    R2,FPSCR
        STMDB   R8!,{R2,R4}             @ Push FPSCR, maintain 8-byte alignment
        VSTMDB  R8!,{S0-S31}
        LDRB    R2,[R3,#TCB_STACKF]     @ Record in TCB that VFP state is stacked
        ORR     R2,#2
        STRB    R2,[R3,#TCB_STACKF]

no_outgoing_vfp:
        STR     R8,[R3,#TCB_TSTACK]
        MOV     R4,LR

        PUSH    {R4}                    @ Push R4 so we can use it as a temp
        AND     R4, SP, #4              @ Ensure stack is 8-byte aligned
        SUB     SP, SP, R4              @ Adjust stack
        PUSH    {R4, LR}                @ Store stack adjustment and dummy LR to SVC stack

        BLX     rt_stk_check

        POP     {R4, LR}                @ Get stack adjustment & discard dummy LR
        ADD     SP, SP, R4              @ Unadjust stack
        POP     {R4}                    @ Restore R4

        MOV     LR,R4

SVC_Next:  @ R4 == os_tsk.run, LR == os_tsk.new, R0-R3, R5-R12 corruptible
        LDR     R1,=os_tsk              @ __cpp(&os_tsk), os_tsk.run = os_tsk.new
        STR     LR,[R1]
        LDRB    R1,[LR,#TCB_TID]        @ os_tsk.run->task_id
        LSL     R1,#8                   @ Store PROCID
        MCR     p15,0,R1,c13,c0,1       @ Write CONTEXTIDR

        LDR     R0,[LR,#TCB_TSTACK]     @ os_tsk.run->tsk_stack

        @ Does incoming task have VFP state in stack?
        LDRB    R3,[LR,#TCB_STACKF]
        TST     R3,#0x2
        MRC     p15,0,R1,c1,c0,2        @ Read CPACR
        ANDEQ   R1,R1,#0xFF0FFFFF       @ Disable VFP access if incoming task does not have stacked VFP state
        ORRNE   R1,R1,#0x00F00000       @ Enable VFP access if incoming task does have stacked VFP state
        MCR     p15,0,R1,c1,c0,2        @ Write CPACR
        BEQ     no_incoming_vfp
        ISB                             @ We only need the sync if we enabled, otherwise we will context switch before next VFP instruction anyway
        VLDMIA  R0!,{S0-S31}
        LDR     R2,[R0]
        VMSR    FPSCR,R2
        ADD     R0,R0,#8

no_incoming_vfp:
        LDR     R1,[R0,#60]             @ Restore User CPSR
        MSR     SPSR_cxsf,R1
        LDMIA   R0!,{R4-R11}            @ Restore User R4-R11
        ADD     R0,R0,#4                @ Restore User R1-R3,R12
        LDMIA   R0!,{R1-R3,R12}
        LDMIA   R0,{LR}^                @ Restore User LR
        ADD     R0,R0,#4                @ No writeback for load to user LR
        LDMIA   R0!,{LR}                @ Restore User PC
        ADD     R0,R0,#4                @ Correct User SP for unstacked user CPSR

        PUSH    {R0}                    @ Push R0 onto stack
        LDMIA   SP,{SP}^                @ Get R0 off stack into User SP
        ADD     SP,SP,#4                @ Put SP back

        LDR     R0,[R0,#-32]            @ Restore R0

        PUSH    {R0-R3,R12,LR}

        AND     R12, SP, #4             @ Ensure stack is 8-byte aligned
        SUB     SP, SP, R12             @ Adjust stack
        PUSH    {R12, LR}               @ Store stack adjustment and dummy LR to SVC stack

        CPSID   i
        BLX     rt_tsk_unlock

        POP     {R12, LR}               @ Get stack adjustment & discard dummy LR
        ADD     SP, SP, R12             @ Unadjust stack

        POP     {R0-R3,R12,LR}

        MOVS    PC,LR                   @ Return from exception


        /*------------------- User SVC -------------------------------*/

SVC_User:
        LDR     R12,=SVC_Count
        LDR     R12,[R12]
        CMP     R4,R12                  @ Check for overflow
        BHI     SVC_Done

        LDR     R12,=SVC_Table-4
        LDR     R12,[R12,R4,LSL #2]     @ Load SVC Function Address
        MRS     R4,SPSR                 @ Save SPSR
        PUSH    {R4}                    @ Push R4 so we can use it as a temp
        AND     R4, SP, #4              @ Ensure stack is 8-byte aligned
        SUB     SP, SP, R4              @ Adjust stack
        PUSH    {R4, LR}                @ Store stack adjustment and dummy LR
        BLX     R12                     @ Call SVC Function
        POP     {R4, LR}                @ Get stack adjustment & discard dummy LR
        ADD     SP, SP, R4              @ Unadjust stack
        POP     {R4}                    @ Restore R4
        MSR     SPSR_cxsf,R4            @ Restore SPSR

SVC_Done:
        PUSH    {R0-R3,R12,LR}

        PUSH    {R4}                    @ Push R4 so we can use it as a temp
        AND     R4, SP, #4              @ Ensure stack is 8-byte aligned
        SUB     SP, SP, R4              @ Adjust stack
        PUSH    {R4, LR}                @ Store stack adjustment and dummy LR

        CPSID   i
        BLX     rt_tsk_unlock

        POP     {R4, LR}                @ Get stack adjustment & discard dummy LR
        ADD     SP, SP, R4              @ Unadjust stack
        POP     {R4}                    @ Restore R4

        POP     {R0-R3,R12,LR}
        POP     {R4}
        RFEFD   SP!                     @ Return from exception

@ }

@ #pragma pop


@ #pragma push
@ #pragma arm
@ __asm void PendSV_Handler (U32 IRQn) {
PendSV_Handler:
    .arm

    .extern  rt_tsk_lock
    .extern  IRQNestLevel

    ADD     SP,SP,#8 @ fix up stack pointer (R0 has been pushed and will never be popped, R1 was pushed for stack alignment)

    @ Disable systick interrupts, then write EOIR. We want interrupts disabled before we enter the context switcher.
    PUSH    {R0, R1}
    BLX     rt_tsk_lock
    POP     {R0, R1}
    LDR     R1, =GICInterface_BASE      @ __cpp(&GICInterface_BASE)
    LDR     R1, [R1, #0]
    STR     R0, [R1, #0x10]

    LDR     R0, =IRQNestLevel           @ Get address of nesting counter
    LDR     R1, [R0]
    SUB     R1, R1, #1                  @ Decrement nesting counter
    STR     R1, [R0]

    BLX     rt_pop_req                  @ __cpp(rt_pop_req)

    POP     {R1, LR}                @ Get stack adjustment & discard dummy LR
    ADD     SP, SP, R1              @ Unadjust stack

    LDR     R0,[SP,#24]
    MSR     SPSR_cxsf,R0
    POP     {R0-R3,R12}             @ Leave SPSR & LR on the stack
    PUSH    {R4}
    B       Sys_Switch
@ }
@ #pragma pop

@ #pragma push
@ #pragma arm
@ __asm void OS_Tick_Handler (U32 IRQn) {
OS_Tick_Handler:
    .arm

    ADD     SP,SP,#8 @ fix up stack pointer (R0 has been pushed and will never be popped, R1 was pushed for stack alignment)

    PUSH    {R0, R1}
    BLX     rt_tsk_lock
    POP     {R0, R1}
    LDR     R1, =GICInterface_BASE      @ __cpp(&GICInterface_BASE)
    LDR     R1, [R1, #0]
    STR     R0, [R1, #0x10]

    LDR     R0, =IRQNestLevel           @ Get address of nesting counter
    LDR     R1, [R0]
    SUB     R1, R1, #1                  @ Decrement nesting counter
    STR     R1, [R0]

    BLX      os_tick_irqack             @ __cpp(os_tick_irqack)
    BLX      rt_systick                 @ __cpp(rt_systick)

    POP     {R1, LR}                @ Get stack adjustment & discard dummy LR
    ADD     SP, SP, R1              @ Unadjust stack

    LDR     R0,[SP,#24]
    MSR     SPSR_cxsf,R0
    POP     {R0-R3,R12}             @ Leave SPSR & LR on the stack
    PUSH    {R4}
    B       Sys_Switch
@ }
@ #pragma pop

    .global __set_PSP
@ __STATIC_ASM void __set_PSP(uint32_t topOfProcStack)
@ {
__set_PSP:
@     PRESERVE8
    .arm

    BIC     R0, R0, #7  @ensure stack is 8-byte aligned
    MRS     R1, CPSR
    CPS     #MODE_SYS   @no effect in USR mode
    MOV     SP, R0
    MSR     CPSR_c, R1  @no effect in USR mode
    ISB
    BX      LR

@ }

    .global __set_CPS_USR
@ __STATIC_ASM void __set_CPS_USR(void)
@ {
__set_CPS_USR:
    .arm

    CPS  #MODE_USR
    BX   LR
@ }

    .END
/*----------------------------------------------------------------------------
 * end of file
 *---------------------------------------------------------------------------*/