xref: /nrf52832-nimble/rt-thread/libcpu/arm/cortex-m3/context_gcc.S (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero/*
2*10465441SEvalZero * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero *
4*10465441SEvalZero * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero *
6*10465441SEvalZero * Change Logs:
7*10465441SEvalZero * Date         Author    Notes
8*10465441SEvalZero * 2009-10-11   Bernard   First version
9*10465441SEvalZero * 2010-12-29   onelife   Modify for EFM32
10*10465441SEvalZero * 2011-06-17   onelife   Merge all of the assembly source code into context_gcc.S
11*10465441SEvalZero * 2011-07-12   onelife   Add interrupt context check function
12*10465441SEvalZero * 2013-06-18   aozima    add restore MSP feature.
13*10465441SEvalZero * 2013-07-09   aozima    enhancement hard fault exception handler.
14*10465441SEvalZero */
15*10465441SEvalZero
16*10465441SEvalZero    .cpu    cortex-m3
17*10465441SEvalZero    .fpu    softvfp
18*10465441SEvalZero    .syntax unified
19*10465441SEvalZero    .thumb
20*10465441SEvalZero    .text
21*10465441SEvalZero
22*10465441SEvalZero    .equ    SCB_VTOR, 0xE000ED08            /* Vector Table Offset Register */
23*10465441SEvalZero    .equ    ICSR, 0xE000ED04                /* interrupt control state register */
24*10465441SEvalZero    .equ    PENDSVSET_BIT, 0x10000000       /* value to trigger PendSV exception */
25*10465441SEvalZero
26*10465441SEvalZero    .equ    SHPR3, 0xE000ED20               /* system priority register (3) */
27*10465441SEvalZero    .equ    PENDSV_PRI_LOWEST, 0x00FF0000   /* PendSV priority value (lowest) */
28*10465441SEvalZero
29*10465441SEvalZero/*
30*10465441SEvalZero * rt_base_t rt_hw_interrupt_disable();
31*10465441SEvalZero */
32*10465441SEvalZero    .global rt_hw_interrupt_disable
33*10465441SEvalZero    .type rt_hw_interrupt_disable, %function
34*10465441SEvalZerort_hw_interrupt_disable:
35*10465441SEvalZero    MRS     R0, PRIMASK
36*10465441SEvalZero    CPSID   I
37*10465441SEvalZero    BX      LR
38*10465441SEvalZero
39*10465441SEvalZero/*
40*10465441SEvalZero * void rt_hw_interrupt_enable(rt_base_t level);
41*10465441SEvalZero */
42*10465441SEvalZero    .global rt_hw_interrupt_enable
43*10465441SEvalZero    .type rt_hw_interrupt_enable, %function
44*10465441SEvalZerort_hw_interrupt_enable:
45*10465441SEvalZero    MSR     PRIMASK, R0
46*10465441SEvalZero    BX      LR
47*10465441SEvalZero
48*10465441SEvalZero/*
49*10465441SEvalZero * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
50*10465441SEvalZero * R0 --> from
51*10465441SEvalZero * R1 --> to
52*10465441SEvalZero */
53*10465441SEvalZero    .global rt_hw_context_switch_interrupt
54*10465441SEvalZero    .type rt_hw_context_switch_interrupt, %function
55*10465441SEvalZero    .global rt_hw_context_switch
56*10465441SEvalZero    .type rt_hw_context_switch, %function
57*10465441SEvalZerort_hw_context_switch_interrupt:
58*10465441SEvalZerort_hw_context_switch:
59*10465441SEvalZero    /* set rt_thread_switch_interrupt_flag to 1 */
60*10465441SEvalZero    LDR     R2, =rt_thread_switch_interrupt_flag
61*10465441SEvalZero    LDR     R3, [R2]
62*10465441SEvalZero    CMP     R3, #1
63*10465441SEvalZero    BEQ     _reswitch
64*10465441SEvalZero    MOV     R3, #1
65*10465441SEvalZero    STR     R3, [R2]
66*10465441SEvalZero
67*10465441SEvalZero    LDR     R2, =rt_interrupt_from_thread   /* set rt_interrupt_from_thread */
68*10465441SEvalZero    STR     R0, [R2]
69*10465441SEvalZero
70*10465441SEvalZero_reswitch:
71*10465441SEvalZero    LDR     R2, =rt_interrupt_to_thread     /* set rt_interrupt_to_thread */
72*10465441SEvalZero    STR     R1, [R2]
73*10465441SEvalZero
74*10465441SEvalZero    LDR     R0, =ICSR           /* trigger the PendSV exception (causes context switch) */
75*10465441SEvalZero    LDR     R1, =PENDSVSET_BIT
76*10465441SEvalZero    STR     R1, [R0]
77*10465441SEvalZero    BX      LR
78*10465441SEvalZero
79*10465441SEvalZero/* R0 --> switch from thread stack
80*10465441SEvalZero * R1 --> switch to thread stack
81*10465441SEvalZero * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
82*10465441SEvalZero */
83*10465441SEvalZero    .global PendSV_Handler
84*10465441SEvalZero    .type PendSV_Handler, %function
85*10465441SEvalZeroPendSV_Handler:
86*10465441SEvalZero    /* disable interrupt to protect context switch */
87*10465441SEvalZero    MRS     R2, PRIMASK
88*10465441SEvalZero    CPSID   I
89*10465441SEvalZero
90*10465441SEvalZero    /* get rt_thread_switch_interrupt_flag */
91*10465441SEvalZero    LDR     R0, =rt_thread_switch_interrupt_flag
92*10465441SEvalZero    LDR     R1, [R0]
93*10465441SEvalZero    CBZ     R1, pendsv_exit         /* pendsv aLReady handled */
94*10465441SEvalZero
95*10465441SEvalZero    /* clear rt_thread_switch_interrupt_flag to 0 */
96*10465441SEvalZero    MOV     R1, #0
97*10465441SEvalZero    STR     R1, [R0]
98*10465441SEvalZero
99*10465441SEvalZero    LDR     R0, =rt_interrupt_from_thread
100*10465441SEvalZero    LDR     R1, [R0]
101*10465441SEvalZero    CBZ     R1, switch_to_thread    /* skip register save at the first time */
102*10465441SEvalZero
103*10465441SEvalZero    MRS     R1, PSP                 /* get from thread stack pointer */
104*10465441SEvalZero    STMFD   R1!, {R4 - R11}         /* push R4 - R11 register */
105*10465441SEvalZero    LDR     R0, [R0]
106*10465441SEvalZero    STR     R1, [R0]                /* update from thread stack pointer */
107*10465441SEvalZero
108*10465441SEvalZeroswitch_to_thread:
109*10465441SEvalZero    LDR     R1, =rt_interrupt_to_thread
110*10465441SEvalZero    LDR     R1, [R1]
111*10465441SEvalZero    LDR     R1, [R1]                /* load thread stack pointer */
112*10465441SEvalZero
113*10465441SEvalZero    LDMFD   R1!, {R4 - R11}         /* pop R4 - R11 register */
114*10465441SEvalZero    MSR     PSP, R1                 /* update stack pointer */
115*10465441SEvalZero
116*10465441SEvalZeropendsv_exit:
117*10465441SEvalZero    /* restore interrupt */
118*10465441SEvalZero    MSR     PRIMASK, R2
119*10465441SEvalZero
120*10465441SEvalZero    ORR     LR, LR, #0x04
121*10465441SEvalZero    BX      LR
122*10465441SEvalZero
123*10465441SEvalZero/*
124*10465441SEvalZero * void rt_hw_context_switch_to(rt_uint32 to);
125*10465441SEvalZero * R0 --> to
126*10465441SEvalZero */
127*10465441SEvalZero    .global rt_hw_context_switch_to
128*10465441SEvalZero    .type rt_hw_context_switch_to, %function
129*10465441SEvalZerort_hw_context_switch_to:
130*10465441SEvalZero    LDR     R1, =rt_interrupt_to_thread
131*10465441SEvalZero    STR     R0, [R1]
132*10465441SEvalZero
133*10465441SEvalZero    /* set from thread to 0 */
134*10465441SEvalZero    LDR     R1, =rt_interrupt_from_thread
135*10465441SEvalZero    MOV     R0, #0
136*10465441SEvalZero    STR     R0, [R1]
137*10465441SEvalZero
138*10465441SEvalZero    /* set interrupt flag to 1 */
139*10465441SEvalZero    LDR     R1, =rt_thread_switch_interrupt_flag
140*10465441SEvalZero    MOV     R0, #1
141*10465441SEvalZero    STR     R0, [R1]
142*10465441SEvalZero
143*10465441SEvalZero    /* set the PendSV exception priority */
144*10465441SEvalZero    LDR     R0, =SHPR3
145*10465441SEvalZero    LDR     R1, =PENDSV_PRI_LOWEST
146*10465441SEvalZero    LDR.W   R2, [R0,#0]             /* read */
147*10465441SEvalZero    ORR     R1, R1, R2              /* modify */
148*10465441SEvalZero    STR     R1, [R0]                /* write-back */
149*10465441SEvalZero
150*10465441SEvalZero    LDR     R0, =ICSR               /* trigger the PendSV exception (causes context switch) */
151*10465441SEvalZero    LDR     R1, =PENDSVSET_BIT
152*10465441SEvalZero    STR     R1, [R0]
153*10465441SEvalZero
154*10465441SEvalZero    /* restore MSP */
155*10465441SEvalZero    LDR     r0, =SCB_VTOR
156*10465441SEvalZero    LDR     r0, [r0]
157*10465441SEvalZero    LDR     r0, [r0]
158*10465441SEvalZero    NOP
159*10465441SEvalZero    MSR     msp, r0
160*10465441SEvalZero
161*10465441SEvalZero    /* enable interrupts at processor level */
162*10465441SEvalZero    CPSIE   F
163*10465441SEvalZero    CPSIE   I
164*10465441SEvalZero
165*10465441SEvalZero    /* never reach here! */
166*10465441SEvalZero
167*10465441SEvalZero/* compatible with old version */
168*10465441SEvalZero    .global rt_hw_interrupt_thread_switch
169*10465441SEvalZero    .type rt_hw_interrupt_thread_switch, %function
170*10465441SEvalZerort_hw_interrupt_thread_switch:
171*10465441SEvalZero    BX      LR
172*10465441SEvalZero    NOP
173*10465441SEvalZero
174*10465441SEvalZero    .global HardFault_Handler
175*10465441SEvalZero    .type HardFault_Handler, %function
176*10465441SEvalZeroHardFault_Handler:
177*10465441SEvalZero    /* get current context */
178*10465441SEvalZero    MRS     r0, msp                 /* get fault context from handler. */
179*10465441SEvalZero    TST     lr, #0x04               /* if(!EXC_RETURN[2]) */
180*10465441SEvalZero    BEQ     _get_sp_done
181*10465441SEvalZero    MRS     r0, psp                 /* get fault context from thread. */
182*10465441SEvalZero_get_sp_done:
183*10465441SEvalZero
184*10465441SEvalZero    STMFD   r0!, {r4 - r11}         /* push r4 - r11 register */
185*10465441SEvalZero    STMFD   r0!, {lr}               /* push exec_return register */
186*10465441SEvalZero
187*10465441SEvalZero    TST     lr, #0x04               /* if(!EXC_RETURN[2]) */
188*10465441SEvalZero    BEQ     _update_msp
189*10465441SEvalZero    MSR     psp, r0                 /* update stack pointer to PSP. */
190*10465441SEvalZero    B       _update_done
191*10465441SEvalZero_update_msp:
192*10465441SEvalZero    MSR     msp, r0                 /* update stack pointer to MSP. */
193*10465441SEvalZero_update_done:
194*10465441SEvalZero
195*10465441SEvalZero    PUSH    {LR}
196*10465441SEvalZero    BL      rt_hw_hard_fault_exception
197*10465441SEvalZero    POP     {LR}
198*10465441SEvalZero
199*10465441SEvalZero    ORR     LR, LR, #0x04
200*10465441SEvalZero    BX      LR
201*10465441SEvalZero
202*10465441SEvalZero/*
203*10465441SEvalZero * rt_uint32_t rt_hw_interrupt_check(void);
204*10465441SEvalZero * R0 --> state
205*10465441SEvalZero */
206*10465441SEvalZero    .global rt_hw_interrupt_check
207*10465441SEvalZero    .type rt_hw_interrupt_check, %function
208*10465441SEvalZerort_hw_interrupt_check:
209*10465441SEvalZero    MRS     R0, IPSR
210*10465441SEvalZero    BX      LR
211