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