xref: /nrf52832-nimble/rt-thread/libcpu/arm/cortex-m3/context_iar.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; * 2009-09-27     Bernard      add protect when contex switch occurs
10; * 2013-06-18     aozima       add restore MSP feature.
11; * 2013-07-09     aozima       enhancement hard fault exception handler.
12; */
13
14;/**
15; * @addtogroup cortex-m3
16; */
17;/*@{*/
18
19SCB_VTOR        EQU     0xE000ED08               ; Vector Table Offset Register
20NVIC_INT_CTRL   EQU     0xE000ED04               ; interrupt control state register
21NVIC_SYSPRI2    EQU     0xE000ED20               ; system priority register (2)
22NVIC_PENDSV_PRI EQU     0x00FF0000               ; PendSV priority value (lowest)
23NVIC_PENDSVSET  EQU     0x10000000               ; value to trigger PendSV exception
24
25    SECTION    .text:CODE(2)
26    THUMB
27    REQUIRE8
28    PRESERVE8
29
30    IMPORT rt_thread_switch_interrupt_flag
31    IMPORT rt_interrupt_from_thread
32    IMPORT rt_interrupt_to_thread
33
34;/*
35; * rt_base_t rt_hw_interrupt_disable();
36; */
37    EXPORT rt_hw_interrupt_disable
38rt_hw_interrupt_disable:
39    MRS     r0, PRIMASK
40    CPSID   I
41    BX      LR
42
43;/*
44; * void rt_hw_interrupt_enable(rt_base_t level);
45; */
46    EXPORT  rt_hw_interrupt_enable
47rt_hw_interrupt_enable:
48    MSR     PRIMASK, r0
49    BX      LR
50
51;/*
52; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
53; * r0 --> from
54; * r1 --> to
55; */
56    EXPORT rt_hw_context_switch_interrupt
57    EXPORT rt_hw_context_switch
58rt_hw_context_switch_interrupt:
59rt_hw_context_switch:
60    ; set rt_thread_switch_interrupt_flag to 1
61    LDR     r2, =rt_thread_switch_interrupt_flag
62    LDR     r3, [r2]
63    CMP     r3, #1
64    BEQ     _reswitch
65    MOV     r3, #1
66    STR     r3, [r2]
67
68    LDR     r2, =rt_interrupt_from_thread   ; set rt_interrupt_from_thread
69    STR     r0, [r2]
70
71_reswitch
72    LDR     r2, =rt_interrupt_to_thread     ; set rt_interrupt_to_thread
73    STR     r1, [r2]
74
75    LDR     r0, =NVIC_INT_CTRL              ; trigger the PendSV exception (causes context switch)
76    LDR     r1, =NVIC_PENDSVSET
77    STR     r1, [r0]
78    BX      LR
79
80; r0 --> switch from thread stack
81; r1 --> switch to thread stack
82; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
83    EXPORT PendSV_Handler
84PendSV_Handler:
85
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, #0x00
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    EXPORT rt_hw_context_switch_to
128rt_hw_context_switch_to:
129    LDR     r1, =rt_interrupt_to_thread
130    STR     r0, [r1]
131
132    ; set from thread to 0
133    LDR     r1, =rt_interrupt_from_thread
134    MOV     r0, #0x0
135    STR     r0, [r1]
136
137    ; set interrupt flag to 1
138    LDR     r1, =rt_thread_switch_interrupt_flag
139    MOV     r0, #1
140    STR     r0, [r1]
141
142    ; set the PendSV exception priority
143    LDR     r0, =NVIC_SYSPRI2
144    LDR     r1, =NVIC_PENDSV_PRI
145    LDR.W   r2, [r0,#0x00]       ; read
146    ORR     r1,r1,r2             ; modify
147    STR     r1, [r0]             ; write-back
148
149    LDR     r0, =NVIC_INT_CTRL      ; trigger the PendSV exception (causes context switch)
150    LDR     r1, =NVIC_PENDSVSET
151    STR     r1, [r0]
152
153    ; restore MSP
154    LDR     r0, =SCB_VTOR
155    LDR     r0, [r0]
156    LDR     r0, [r0]
157    NOP
158    MSR     msp, r0
159
160    ; enable interrupts at processor level
161    CPSIE   F
162    CPSIE   I
163
164    ; never reach here!
165
166; compatible with old version
167    EXPORT rt_hw_interrupt_thread_switch
168rt_hw_interrupt_thread_switch:
169    BX      lr
170
171    IMPORT rt_hw_hard_fault_exception
172    EXPORT HardFault_Handler
173HardFault_Handler:
174
175    ; get current context
176    MRS     r0, msp                 ; get fault context from handler.
177    TST     lr, #0x04               ; if(!EXC_RETURN[2])
178    BEQ     _get_sp_done
179    MRS     r0, psp                 ; get fault context from thread.
180_get_sp_done
181
182    STMFD   r0!, {r4 - r11}         ; push r4 - r11 register
183    ;STMFD   r0!, {lr}               ; push exec_return register
184    SUB     r0, r0, #0x04
185    STR     lr, [r0]
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    END
203