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