xref: /nrf52832-nimble/rt-thread/libcpu/arm/cortex-m3/context_rvds.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-01-17     Bernard      first version
9; * 2013-06-18     aozima       add restore MSP feature.
10; * 2013-07-09     aozima       enhancement hard fault exception handler.
11; */
12
13;/**
14; * @addtogroup CORTEX-M3
15; */
16;/*@{*/
17
18SCB_VTOR        EQU     0xE000ED08               ; Vector Table Offset Register
19NVIC_INT_CTRL   EQU     0xE000ED04               ; interrupt control state register
20NVIC_SYSPRI2    EQU     0xE000ED20               ; system priority register (2)
21NVIC_PENDSV_PRI EQU     0x00FF0000               ; PendSV priority value (lowest)
22NVIC_PENDSVSET  EQU     0x10000000               ; value to trigger PendSV exception
23
24    AREA |.text|, CODE, READONLY, ALIGN=2
25    THUMB
26    REQUIRE8
27    PRESERVE8
28
29    IMPORT rt_thread_switch_interrupt_flag
30    IMPORT rt_interrupt_from_thread
31    IMPORT rt_interrupt_to_thread
32
33;/*
34; * rt_base_t rt_hw_interrupt_disable();
35; */
36rt_hw_interrupt_disable    PROC
37    EXPORT  rt_hw_interrupt_disable
38    MRS     r0, PRIMASK
39    CPSID   I
40    BX      LR
41    ENDP
42
43;/*
44; * void rt_hw_interrupt_enable(rt_base_t level);
45; */
46rt_hw_interrupt_enable    PROC
47    EXPORT  rt_hw_interrupt_enable
48    MSR     PRIMASK, r0
49    BX      LR
50    ENDP
51
52;/*
53; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
54; * r0 --> from
55; * r1 --> to
56; */
57rt_hw_context_switch_interrupt
58    EXPORT rt_hw_context_switch_interrupt
59rt_hw_context_switch    PROC
60    EXPORT rt_hw_context_switch
61
62    ; set rt_thread_switch_interrupt_flag to 1
63    LDR     r2, =rt_thread_switch_interrupt_flag
64    LDR     r3, [r2]
65    CMP     r3, #1
66    BEQ     _reswitch
67    MOV     r3, #1
68    STR     r3, [r2]
69
70    LDR     r2, =rt_interrupt_from_thread   ; set rt_interrupt_from_thread
71    STR     r0, [r2]
72
73_reswitch
74    LDR     r2, =rt_interrupt_to_thread     ; set rt_interrupt_to_thread
75    STR     r1, [r2]
76
77    LDR     r0, =NVIC_INT_CTRL              ; trigger the PendSV exception (causes context switch)
78    LDR     r1, =NVIC_PENDSVSET
79    STR     r1, [r0]
80    BX      LR
81    ENDP
82
83; r0 --> switch from thread stack
84; r1 --> switch to thread stack
85; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
86PendSV_Handler   PROC
87    EXPORT PendSV_Handler
88
89    ; disable interrupt to protect context switch
90    MRS     r2, PRIMASK
91    CPSID   I
92
93    ; get rt_thread_switch_interrupt_flag
94    LDR     r0, =rt_thread_switch_interrupt_flag
95    LDR     r1, [r0]
96    CBZ     r1, pendsv_exit         ; pendsv already handled
97
98    ; clear rt_thread_switch_interrupt_flag to 0
99    MOV     r1, #0x00
100    STR     r1, [r0]
101
102    LDR     r0, =rt_interrupt_from_thread
103    LDR     r1, [r0]
104    CBZ     r1, switch_to_thread    ; skip register save at the first time
105
106    MRS     r1, psp                 ; get from thread stack pointer
107    STMFD   r1!, {r4 - r11}         ; push r4 - r11 register
108    LDR     r0, [r0]
109    STR     r1, [r0]                ; update from thread stack pointer
110
111switch_to_thread
112    LDR     r1, =rt_interrupt_to_thread
113    LDR     r1, [r1]
114    LDR     r1, [r1]                ; load thread stack pointer
115
116    LDMFD   r1!, {r4 - r11}         ; pop r4 - r11 register
117    MSR     psp, r1                 ; update stack pointer
118
119pendsv_exit
120    ; restore interrupt
121    MSR     PRIMASK, r2
122
123    ORR     lr, lr, #0x04
124    BX      lr
125    ENDP
126
127;/*
128; * void rt_hw_context_switch_to(rt_uint32 to);
129; * r0 --> to
130; * this fucntion is used to perform the first thread switch
131; */
132rt_hw_context_switch_to    PROC
133    EXPORT rt_hw_context_switch_to
134    ; set to thread
135    LDR     r1, =rt_interrupt_to_thread
136    STR     r0, [r1]
137
138    ; set from thread to 0
139    LDR     r1, =rt_interrupt_from_thread
140    MOV     r0, #0x0
141    STR     r0, [r1]
142
143    ; set interrupt flag to 1
144    LDR     r1, =rt_thread_switch_interrupt_flag
145    MOV     r0, #1
146    STR     r0, [r1]
147
148    ; set the PendSV exception priority
149    LDR     r0, =NVIC_SYSPRI2
150    LDR     r1, =NVIC_PENDSV_PRI
151    LDR.W   r2, [r0,#0x00]       ; read
152    ORR     r1,r1,r2             ; modify
153    STR     r1, [r0]             ; write-back
154
155    ; trigger the PendSV exception (causes context switch)
156    LDR     r0, =NVIC_INT_CTRL
157    LDR     r1, =NVIC_PENDSVSET
158    STR     r1, [r0]
159
160    ; restore MSP
161    LDR     r0, =SCB_VTOR
162    LDR     r0, [r0]
163    LDR     r0, [r0]
164    MSR     msp, r0
165
166    ; enable interrupts at processor level
167    CPSIE   F
168    CPSIE   I
169
170    ; never reach here!
171    ENDP
172
173; compatible with old version
174rt_hw_interrupt_thread_switch PROC
175    EXPORT rt_hw_interrupt_thread_switch
176    BX      lr
177    ENDP
178
179    IMPORT rt_hw_hard_fault_exception
180    EXPORT HardFault_Handler
181HardFault_Handler    PROC
182
183    ; get current context
184    TST     lr, #0x04               ; if(!EXC_RETURN[2])
185    ITE     EQ
186    MRSEQ   r0, msp                 ; [2]=0 ==> Z=1, get fault context from handler.
187    MRSNE   r0, psp                 ; [2]=1 ==> Z=0, get fault context from thread.
188
189    STMFD   r0!, {r4 - r11}         ; push r4 - r11 register
190    STMFD   r0!, {lr}               ; push exec_return register
191
192    TST     lr, #0x04               ; if(!EXC_RETURN[2])
193    ITE     EQ
194    MSREQ   msp, r0                 ; [2]=0 ==> Z=1, update stack pointer to MSP.
195    MSRNE   psp, r0                 ; [2]=1 ==> Z=0, update stack pointer to PSP.
196
197    PUSH    {lr}
198    BL      rt_hw_hard_fault_exception
199    POP     {lr}
200
201    ORR     lr, lr, #0x04
202    BX      lr
203    ENDP
204
205    ALIGN   4
206
207    END
208