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-20 Bernard first version 9; * 2011-07-22 Bernard added thumb mode porting 10; * 2013-05-24 Grissiom port to CCS 11; * 2013-05-26 Grissiom optimize for ARMv7 12; */ 13 14 .text 15 .arm 16 .ref rt_thread_switch_interrupt_flag 17 .ref rt_interrupt_from_thread 18 .ref rt_interrupt_to_thread 19 .ref rt_interrupt_enter 20 .ref rt_interrupt_leave 21 .ref rt_hw_trap_irq 22 23;/* 24; * rt_base_t rt_hw_interrupt_disable(); 25; */ 26 .def rt_hw_interrupt_disable 27 .asmfunc 28rt_hw_interrupt_disable 29 MRS r0, cpsr 30 CPSID IF 31 BX lr 32 .endasmfunc 33 34;/* 35; * void rt_hw_interrupt_enable(rt_base_t level); 36; */ 37 .def rt_hw_interrupt_enable 38 .asmfunc 39rt_hw_interrupt_enable 40 MSR cpsr_c, r0 41 BX lr 42 .endasmfunc 43 44;/* 45; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); 46; * r0 --> from 47; * r1 --> to 48; */ 49 .def rt_hw_context_switch 50 .asmfunc 51rt_hw_context_switch 52 STMDB sp!, {lr} ; push pc (lr should be pushed in place of PC) 53 STMDB sp!, {r0-r12, lr} ; push lr & register file 54 55 MRS r4, cpsr 56 TST lr, #0x01 57 ORRNE r4, r4, #0x20 ; it's thumb code 58 59 STMDB sp!, {r4} ; push cpsr 60 61 .if (__TI_VFP_SUPPORT__) 62 VMRS r4, fpexc 63 TST r4, #0x40000000 64 BEQ __no_vfp_frame1 65 VSTMDB sp!, {d0-d15} 66 VMRS r5, fpscr 67 ; TODO: add support for Common VFPv3. 68 ; Save registers like FPINST, FPINST2 69 STMDB sp!, {r5} 70__no_vfp_frame1 71 STMDB sp!, {r4} 72 .endif 73 74 STR sp, [r0] ; store sp in preempted tasks TCB 75 LDR sp, [r1] ; get new task stack pointer 76 77 .if (__TI_VFP_SUPPORT__) 78 LDMIA sp!, {r0} ; get fpexc 79 VMSR fpexc, r0 ; restore fpexc 80 TST r0, #0x40000000 81 BEQ __no_vfp_frame2 82 LDMIA sp!, {r1} ; get fpscr 83 VMSR fpscr, r1 84 VLDMIA sp!, {d0-d15} 85__no_vfp_frame2 86 .endif 87 88 LDMIA sp!, {r4} ; pop new task cpsr to spsr 89 MSR spsr_cxsf, r4 90 91 LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr 92 .endasmfunc 93 94;/* 95; * void rt_hw_context_switch_to(rt_uint32 to); 96; * r0 --> to 97; */ 98 .def rt_hw_context_switch_to 99 .asmfunc 100rt_hw_context_switch_to 101 LDR sp, [r0] ; get new task stack pointer 102 103 .if (__TI_VFP_SUPPORT__) 104 LDMIA sp!, {r0} ; get fpexc 105 VMSR fpexc, r0 106 TST r0, #0x40000000 107 BEQ __no_vfp_frame_to 108 LDMIA sp!, {r1} ; get fpscr 109 VMSR fpscr, r1 110 VLDMIA sp!, {d0-d15} 111__no_vfp_frame_to 112 .endif 113 114 LDMIA sp!, {r4} ; pop new task cpsr to spsr 115 MSR spsr_cxsf, r4 116 117 LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr 118 .endasmfunc 119 120;/* 121; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); 122; */ 123 124 .def rt_hw_context_switch_interrupt 125 .asmfunc 126rt_hw_context_switch_interrupt 127 LDR r2, pintflag 128 LDR r3, [r2] 129 CMP r3, #1 130 BEQ _reswitch 131 MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1 132 STR r3, [r2] 133 LDR r2, pfromthread ; set rt_interrupt_from_thread 134 STR r0, [r2] 135_reswitch 136 LDR r2, ptothread ; set rt_interrupt_to_thread 137 STR r1, [r2] 138 BX lr 139 .endasmfunc 140 141 .def IRQ_Handler 142IRQ_Handler 143 STMDB sp!, {r0-r12,lr} 144 145 .if (__TI_VFP_SUPPORT__) 146 VMRS r0, fpexc 147 TST r0, #0x40000000 148 BEQ __no_vfp_frame_str_irq 149 VSTMDB sp!, {d0-d15} 150 VMRS r1, fpscr 151 ; TODO: add support for Common VFPv3. 152 ; Save registers like FPINST, FPINST2 153 STMDB sp!, {r1} 154__no_vfp_frame_str_irq 155 STMDB sp!, {r0} 156 .endif 157 158 BL rt_interrupt_enter 159 BL rt_hw_trap_irq 160 BL rt_interrupt_leave 161 162 ; if rt_thread_switch_interrupt_flag set, jump to 163 ; rt_hw_context_switch_interrupt_do and don't return 164 LDR r0, pintflag 165 LDR r1, [r0] 166 CMP r1, #1 167 BEQ rt_hw_context_switch_interrupt_do 168 169 .if (__TI_VFP_SUPPORT__) 170 LDMIA sp!, {r0} ; get fpexc 171 VMSR fpexc, r0 172 TST r0, #0x40000000 173 BEQ __no_vfp_frame_ldr_irq 174 LDMIA sp!, {r1} ; get fpscr 175 VMSR fpscr, r1 176 VLDMIA sp!, {d0-d15} 177__no_vfp_frame_ldr_irq 178 .endif 179 180 LDMIA sp!, {r0-r12,lr} 181 SUBS pc, lr, #4 182 183; /* 184; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) 185; */ 186 .def rt_hw_context_switch_interrupt_do 187rt_hw_context_switch_interrupt_do 188 MOV r1, #0 ; clear flag 189 STR r1, [r0] 190 191 .if (__TI_VFP_SUPPORT__) 192 LDMIA sp!, {r0} ; get fpexc 193 VMSR fpexc, r0 194 TST r0, #0x40000000 195 BEQ __no_vfp_frame_do1 196 LDMIA sp!, {r1} ; get fpscr 197 VMSR fpscr, r1 198 VLDMIA sp!, {d0-d15} 199__no_vfp_frame_do1 200 .endif 201 202 LDMIA sp!, {r0-r12,lr} ; reload saved registers 203 STMDB sp, {r0-r3} ; save r0-r3. We will restore r0-r3 in the SVC 204 ; mode so there is no need to update SP. 205 SUB r1, sp, #16 ; save the right SP value in r1, so we could restore r0-r3. 206 SUB r2, lr, #4 ; save old task's pc to r2 207 208 MRS r3, spsr ; get cpsr of interrupt thread 209 210 ; switch to SVC mode and no interrupt 211 CPSID IF, #0x13 212 213 STMDB sp!, {r2} ; push old task's pc 214 STMDB sp!, {r4-r12,lr} ; push old task's lr,r12-r4 215 LDMIA r1!, {r4-r7} ; restore r0-r3 of the interrupted thread 216 STMDB sp!, {r4-r7} ; push old task's r3-r0. We don't need to push/pop them to 217 ; r0-r3 because we just want to transfer the data and don't 218 ; use them here. 219 STMDB sp!, {r3} ; push old task's cpsr 220 221 .if (__TI_VFP_SUPPORT__) 222 VMRS r0, fpexc 223 TST r0, #0x40000000 224 BEQ __no_vfp_frame_do2 225 VSTMDB sp!, {d0-d15} 226 VMRS r1, fpscr 227 ; TODO: add support for Common VFPv3. 228 ; Save registers like FPINST, FPINST2 229 STMDB sp!, {r1} 230__no_vfp_frame_do2 231 STMDB sp!, {r0} 232 .endif 233 234 LDR r4, pfromthread 235 LDR r5, [r4] 236 STR sp, [r5] ; store sp in preempted tasks's TCB 237 238 LDR r6, ptothread 239 LDR r6, [r6] 240 LDR sp, [r6] ; get new task's stack pointer 241 242 .if (__TI_VFP_SUPPORT__) 243 LDMIA sp!, {r0} ; get fpexc 244 VMSR fpexc, r0 245 TST r0, #0x40000000 246 BEQ __no_vfp_frame_do3 247 LDMIA sp!, {r1} ; get fpscr 248 VMSR fpscr, r1 249 VLDMIA sp!, {d0-d15} 250__no_vfp_frame_do3 251 .endif 252 253 LDMIA sp!, {r4} ; pop new task's cpsr to spsr 254 MSR spsr_cxsf, r4 255 256 LDMIA sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr 257 258pintflag .word rt_thread_switch_interrupt_flag 259pfromthread .word rt_interrupt_from_thread 260ptothread .word rt_interrupt_to_thread 261