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