context_gcc.S 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-03-01 Wangyuqiang first version
  9. */
  10. .syntax unified
  11. .text
  12. .globl rt_thread_switch_interrupt_flag
  13. .globl rt_interrupt_from_thread
  14. .globl rt_interrupt_to_thread
  15. .globl rt_interrupt_enter
  16. .globl rt_interrupt_leave
  17. .globl rt_hw_trap_irq
  18. /*
  19. * rt_base_t rt_hw_interrupt_disable();
  20. */
  21. .globl rt_hw_interrupt_disable
  22. rt_hw_interrupt_disable:
  23. mrs r0, cpsr
  24. cpsid i
  25. bx lr
  26. /*
  27. * void rt_hw_interrupt_enable(rt_base_t level);
  28. */
  29. .globl rt_hw_interrupt_enable
  30. rt_hw_interrupt_enable:
  31. msr cpsr, r0
  32. bx lr
  33. /*
  34. * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to)
  35. * r0 --> from
  36. * r1 --> to
  37. */
  38. .globl rt_hw_context_switch
  39. rt_hw_context_switch:
  40. clrex
  41. stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC)
  42. stmfd sp!, {r0-r12, lr} @ push lr & register file
  43. mrs r4, cpsr
  44. tst lr, #0x01
  45. orrne r4, r4, #0x20 @ it's thumb code
  46. stmfd sp!, {r4} @ push cpsr
  47. #ifdef RT_USING_FPU
  48. /* fpu context */
  49. vmrs r6, fpexc
  50. tst r6, #(1<<30)
  51. beq __no_vfp_frame1
  52. vstmdb sp!, {d0-d15}
  53. vstmdb sp!, {d16-d31}
  54. vmrs r5, fpscr
  55. stmfd sp!, {r5}
  56. __no_vfp_frame1:
  57. stmfd sp!, {r6}
  58. #endif
  59. str sp, [r0] @ store sp in preempted tasks TCB
  60. ldr sp, [r1] @ get new task stack pointer
  61. #ifdef RT_USING_FPU
  62. /* fpu context */
  63. ldmfd sp!, {r6}
  64. vmsr fpexc, r6
  65. tst r6, #(1<<30)
  66. beq __no_vfp_frame2
  67. ldmfd sp!, {r5}
  68. vmsr fpscr, r5
  69. vldmia sp!, {d16-d31}
  70. vldmia sp!, {d0-d15}
  71. __no_vfp_frame2:
  72. #endif
  73. ldmfd sp!, {r1}
  74. msr spsr_cxsf, r1 /* original mode */
  75. ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
  76. /*
  77. * void rt_hw_context_switch_to(rt_uint32 to)
  78. * r0 --> to
  79. */
  80. .globl rt_hw_context_switch_to
  81. rt_hw_context_switch_to:
  82. LDR sp, [r0] @ get new task stack pointer
  83. #ifdef RT_USING_FPU
  84. ldmfd sp!, {r6}
  85. vmsr fpexc, r6
  86. tst r6, #(1<<30)
  87. beq __no_vfp_frame_to
  88. ldmfd sp!, {r5}
  89. vmsr fpscr, r5
  90. vldmia sp!, {d0-d15}
  91. __no_vfp_frame_to:
  92. #endif
  93. LDMIA sp!, {r4} @ pop new task cpsr to spsr
  94. MSR spsr_cxsf, r4
  95. ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
  96. /*
  97. * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to)@
  98. */
  99. .globl rt_hw_context_switch_interrupt
  100. rt_hw_context_switch_interrupt:
  101. LDR r2, =rt_thread_switch_interrupt_flag
  102. LDR r3, [r2]
  103. CMP r3, #1
  104. BEQ _reswitch
  105. MOV r3, #1 @ set rt_thread_switch_interrupt_flag to 1
  106. STR r3, [r2]
  107. LDR r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
  108. STR r0, [r2]
  109. _reswitch:
  110. LDR r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
  111. STR r1, [r2]
  112. BX lr
  113. .globl IRQ_Handler
  114. IRQ_Handler:
  115. STMDB sp!, {r0-r12,lr}
  116. #ifdef RT_USING_FPU
  117. VMRS r0, fpexc
  118. TST r0, #0x40000000
  119. BEQ __no_vfp_frame_str_irq
  120. VSTMDB sp!, {d0-d15}
  121. VMRS r1, fpscr
  122. @ TODO: add support for Common VFPv3.
  123. @ Save registers like FPINST, FPINST2
  124. STMDB sp!, {r1}
  125. __no_vfp_frame_str_irq:
  126. STMDB sp!, {r0}
  127. #endif
  128. BL rt_interrupt_enter
  129. BL rt_hw_trap_irq
  130. BL rt_interrupt_leave
  131. @ if rt_thread_switch_interrupt_flag set, jump to
  132. @ rt_hw_context_switch_interrupt_do and don't return
  133. LDR r0, =rt_thread_switch_interrupt_flag
  134. LDR r1, [r0]
  135. CMP r1, #1
  136. BEQ rt_hw_context_switch_interrupt_do
  137. #ifdef RT_USING_FPU
  138. LDMIA sp!, {r0} @ get fpexc
  139. VMSR fpexc, r0
  140. TST r0, #0x40000000
  141. BEQ __no_vfp_frame_ldr_irq
  142. LDMIA sp!, {r1} @ get fpscr
  143. VMSR fpscr, r1
  144. VLDMIA sp!, {d0-d15}
  145. __no_vfp_frame_ldr_irq:
  146. #endif
  147. LDMIA sp!, {r0-r12,lr}
  148. SUBS pc, lr, #4
  149. /*
  150. * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
  151. */
  152. .globl rt_hw_context_switch_interrupt_do
  153. rt_hw_context_switch_interrupt_do:
  154. MOV r1, #0 @ clear flag
  155. STR r1, [r0]
  156. #ifdef RT_USING_FPU
  157. LDMIA sp!, {r0} @ get fpexc
  158. VMSR fpexc, r0
  159. TST r0, #0x40000000
  160. BEQ __no_vfp_frame_do1
  161. LDMIA sp!, {r1} @ get fpscr
  162. VMSR fpscr, r1
  163. VLDMIA sp!, {d0-d15}
  164. __no_vfp_frame_do1:
  165. #endif
  166. LDMIA sp!, {r0-r12,lr} @ reload saved registers
  167. STMDB sp, {r0-r3} @ save r0-r3. We will restore r0-r3 in the SVC
  168. @ mode so there is no need to update SP.
  169. SUB r1, sp, #16 @ save the right SP value in r1, so we could restore r0-r3.
  170. SUB r2, lr, #4 @ save old task's pc to r2
  171. MRS r3, spsr @ get cpsr of interrupt thread
  172. @ switch to SVC mode and no interrupt
  173. CPSID IF, #0x13
  174. STMDB sp!, {r2} @ push old task's pc
  175. STMDB sp!, {r4-r12,lr} @ push old task's lr,r12-r4
  176. LDMIA r1!, {r4-r7} @ restore r0-r3 of the interrupted thread
  177. STMDB sp!, {r4-r7} @ push old task's r3-r0. We don't need to push/pop them to
  178. @ r0-r3 because we just want to transfer the data and don't
  179. @ use them here.
  180. STMDB sp!, {r3} @ push old task's cpsr
  181. #ifdef RT_USING_FPU
  182. VMRS r0, fpexc
  183. TST r0, #0x40000000
  184. BEQ __no_vfp_frame_do2
  185. VSTMDB sp!, {d0-d15}
  186. VMRS r1, fpscr
  187. @ TODO: add support for Common VFPv3.
  188. @ Save registers like FPINST, FPINST2
  189. STMDB sp!, {r1}
  190. __no_vfp_frame_do2:
  191. STMDB sp!, {r0}
  192. #endif
  193. LDR r4, =rt_interrupt_from_thread
  194. LDR r5, [r4]
  195. STR sp, [r5] @ store sp in preempted tasks's TCB
  196. LDR r6, =rt_interrupt_to_thread
  197. LDR r6, [r6]
  198. LDR sp, [r6] @ get new task's stack pointer
  199. #ifdef RT_USING_FPU
  200. ldmfd sp!, {r6}
  201. vmsr fpexc, r6
  202. tst r6, #(1<<30)
  203. beq __no_vfp_frame_do3
  204. ldmfd sp!, {r5}
  205. vmsr fpscr, r5
  206. vldmia sp!, {d0-d15}
  207. __no_vfp_frame_do3:
  208. #endif
  209. LDMIA sp!, {r4} @ pop new task's cpsr to spsr
  210. MSR spsr_cxsf, r4
  211. ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */