irq_armv7a.s 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. ;/*
  2. ; * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
  3. ; *
  4. ; * SPDX-License-Identifier: Apache-2.0
  5. ; *
  6. ; * Licensed under the Apache License, Version 2.0 (the License); you may
  7. ; * not use this file except in compliance with the License.
  8. ; * You may obtain a copy of the License at
  9. ; *
  10. ; * www.apache.org/licenses/LICENSE-2.0
  11. ; *
  12. ; * Unless required by applicable law or agreed to in writing, software
  13. ; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. ; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. ; * See the License for the specific language governing permissions and
  16. ; * limitations under the License.
  17. ; *
  18. ; * -----------------------------------------------------------------------------
  19. ; *
  20. ; * Project: CMSIS-RTOS RTX
  21. ; * Title: ARMv7-A Exception handlers
  22. ; *
  23. ; * -----------------------------------------------------------------------------
  24. ; */
  25. MODE_FIQ EQU 0x11
  26. MODE_IRQ EQU 0x12
  27. MODE_SVC EQU 0x13
  28. MODE_ABT EQU 0x17
  29. MODE_UND EQU 0x1B
  30. CPSR_BIT_T EQU 0x20
  31. K_STATE_RUNNING EQU 2 ; osKernelState_t::osKernelRunning
  32. I_K_STATE_OFS EQU 8 ; osRtxInfo.kernel.state offset
  33. I_TICK_IRQN_OFS EQU 16 ; osRtxInfo.tick_irqn offset
  34. I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
  35. TCB_SP_FRAME EQU 34 ; osRtxThread_t.stack_frame offset
  36. TCB_SP_OFS EQU 56 ; osRtxThread_t.sp offset
  37. PRESERVE8
  38. ARM
  39. AREA |.constdata|, DATA, READONLY
  40. EXPORT irqRtxLib
  41. irqRtxLib DCB 0 ; Non weak library reference
  42. AREA |.data|, DATA, READWRITE
  43. EXPORT IRQ_PendSV
  44. IRQ_NestLevel DCD 0 ; IRQ nesting level counter
  45. IRQ_PendSV DCB 0 ; Pending SVC flag
  46. AREA |.text|, CODE, READONLY
  47. Undef_Handler\
  48. PROC
  49. EXPORT Undef_Handler
  50. IMPORT CUndefHandler
  51. SRSFD SP!, #MODE_UND
  52. PUSH {R0-R4, R12} ; Save APCS corruptible registers to UND mode stack
  53. MRS R0, SPSR
  54. TST R0, #CPSR_BIT_T ; Check mode
  55. MOVEQ R1, #4 ; R1 = 4 ARM mode
  56. MOVNE R1, #2 ; R1 = 2 Thumb mode
  57. SUB R0, LR, R1
  58. LDREQ R0, [R0] ; ARM mode - R0 points to offending instruction
  59. BEQ Undef_Cont
  60. ; Thumb instruction
  61. ; Determine if it is a 32-bit Thumb instruction
  62. LDRH R0, [R0]
  63. MOV R2, #0x1C
  64. CMP R2, R0, LSR #11
  65. BHS Undef_Cont ; 16-bit Thumb instruction
  66. ; 32-bit Thumb instruction. Unaligned - reconstruct the offending instruction
  67. LDRH R2, [LR]
  68. ORR R0, R2, R0, LSL #16
  69. Undef_Cont
  70. MOV R2, LR ; Set LR to third argument
  71. AND R12, SP, #4 ; Ensure stack is 8-byte aligned
  72. SUB SP, SP, R12 ; Adjust stack
  73. PUSH {R12, LR} ; Store stack adjustment and dummy LR
  74. ; R0 =Offending instruction, R1 =2(Thumb) or =4(ARM)
  75. BL CUndefHandler
  76. POP {R12, LR} ; Get stack adjustment & discard dummy LR
  77. ADD SP, SP, R12 ; Unadjust stack
  78. LDR LR, [SP, #24] ; Restore stacked LR and possibly adjust for retry
  79. SUB LR, LR, R0
  80. LDR R0, [SP, #28] ; Restore stacked SPSR
  81. MSR SPSR_CXSF, R0
  82. CLREX ; Clear exclusive monitor
  83. POP {R0-R4, R12} ; Restore stacked APCS registers
  84. ADD SP, SP, #8 ; Adjust SP for already-restored banked registers
  85. MOVS PC, LR
  86. ENDP
  87. PAbt_Handler\
  88. PROC
  89. EXPORT PAbt_Handler
  90. IMPORT CPAbtHandler
  91. SUB LR, LR, #4 ; Pre-adjust LR
  92. SRSFD SP!, #MODE_ABT ; Save LR and SPRS to ABT mode stack
  93. PUSH {R0-R4, R12} ; Save APCS corruptible registers to ABT mode stack
  94. MRC p15, 0, R0, c5, c0, 1 ; IFSR
  95. MRC p15, 0, R1, c6, c0, 2 ; IFAR
  96. MOV R2, LR ; Set LR to third argument
  97. AND R12, SP, #4 ; Ensure stack is 8-byte aligned
  98. SUB SP, SP, R12 ; Adjust stack
  99. PUSH {R12, LR} ; Store stack adjustment and dummy LR
  100. BL CPAbtHandler
  101. POP {R12, LR} ; Get stack adjustment & discard dummy LR
  102. ADD SP, SP, R12 ; Unadjust stack
  103. CLREX ; Clear exclusive monitor
  104. POP {R0-R4, R12} ; Restore stack APCS registers
  105. RFEFD SP! ; Return from exception
  106. ENDP
  107. DAbt_Handler\
  108. PROC
  109. EXPORT DAbt_Handler
  110. IMPORT CDAbtHandler
  111. SUB LR, LR, #8 ; Pre-adjust LR
  112. SRSFD SP!, #MODE_ABT ; Save LR and SPRS to ABT mode stack
  113. PUSH {R0-R4, R12} ; Save APCS corruptible registers to ABT mode stack
  114. MRC p15, 0, R0, c5, c0, 0 ; DFSR
  115. MRC p15, 0, R1, c6, c0, 0 ; DFAR
  116. MOV R2, LR ; Set LR to third argument
  117. AND R12, SP, #4 ; Ensure stack is 8-byte aligned
  118. SUB SP, SP, R12 ; Adjust stack
  119. PUSH {R12, LR} ; Store stack adjustment and dummy LR
  120. BL CDAbtHandler
  121. POP {R12, LR} ; Get stack adjustment & discard dummy LR
  122. ADD SP, SP, R12 ; Unadjust stack
  123. CLREX ; Clear exclusive monitor
  124. POP {R0-R4, R12} ; Restore stacked APCS registers
  125. RFEFD SP! ; Return from exception
  126. ENDP
  127. IRQ_Handler\
  128. PROC
  129. EXPORT IRQ_Handler
  130. IMPORT IRQ_GetActiveIRQ
  131. IMPORT IRQ_GetHandler
  132. IMPORT IRQ_EndOfInterrupt
  133. SUB LR, LR, #4 ; Pre-adjust LR
  134. SRSFD SP!, #MODE_SVC ; Save LR_irq and SPSR_irq on to the SVC stack
  135. CPS #MODE_SVC ; Change to SVC mode
  136. PUSH {R0-R3, R12, LR} ; Save APCS corruptible registers
  137. LDR R0, =IRQ_NestLevel
  138. LDR R1, [R0]
  139. ADD R1, R1, #1 ; Increment IRQ nesting level
  140. STR R1, [R0]
  141. MOV R3, SP ; Move SP into R3
  142. AND R3, R3, #4 ; Get stack adjustment to ensure 8-byte alignment
  143. SUB SP, SP, R3 ; Adjust stack
  144. PUSH {R3, R4} ; Store stack adjustment(R3) and user data(R4)
  145. BLX IRQ_GetActiveIRQ ; Retrieve interrupt ID into R0
  146. MOV R4, R0 ; Move interrupt ID to R4
  147. BLX IRQ_GetHandler ; Retrieve interrupt handler address for current ID
  148. CMP R0, #0 ; Check if handler address is 0
  149. BEQ IRQ_End ; If 0, end interrupt and return
  150. CPSIE i ; Re-enable interrupts
  151. BLX R0 ; Call IRQ handler
  152. CPSID i ; Disable interrupts
  153. IRQ_End
  154. MOV R0, R4 ; Move interrupt ID to R0
  155. BLX IRQ_EndOfInterrupt ; Signal end of interrupt
  156. POP {R3, R4} ; Restore stack adjustment(R3) and user data(R4)
  157. ADD SP, SP, R3 ; Unadjust stack
  158. BL osRtxContextSwitch ; Continue in context switcher
  159. LDR R0, =IRQ_NestLevel
  160. LDR R1, [R0]
  161. SUBS R1, R1, #1 ; Decrement IRQ nesting level
  162. STR R1, [R0]
  163. CLREX ; Clear exclusive monitor for interrupted code
  164. POP {R0-R3, R12, LR} ; Restore stacked APCS registers
  165. RFEFD SP! ; Return from IRQ handler
  166. ENDP
  167. SVC_Handler\
  168. PROC
  169. EXPORT SVC_Handler
  170. IMPORT IRQ_Disable
  171. IMPORT IRQ_Enable
  172. IMPORT osRtxUserSVC
  173. IMPORT osRtxInfo
  174. SRSFD SP!, #MODE_SVC ; Store SPSR_svc and LR_svc onto SVC stack
  175. PUSH {R12, LR}
  176. MRS R12, SPSR ; Load SPSR
  177. TST R12, #CPSR_BIT_T ; Thumb bit set?
  178. LDRHNE R12, [LR,#-2] ; Thumb: load halfword
  179. BICNE R12, R12, #0xFF00 ; extract SVC number
  180. LDREQ R12, [LR,#-4] ; ARM: load word
  181. BICEQ R12, R12, #0xFF000000 ; extract SVC number
  182. CMP R12, #0 ; Compare SVC number
  183. BNE SVC_User ; Branch if User SVC
  184. PUSH {R0-R3} ; Push arguments to stack
  185. LDR R0, =IRQ_NestLevel
  186. LDR R1, [R0]
  187. ADD R1, R1, #1 ; Increment IRQ nesting level
  188. STR R1, [R0]
  189. LDR R0, =osRtxInfo
  190. LDR R1, [R0, #I_K_STATE_OFS] ; Load RTX5 kernel state
  191. CMP R1, #K_STATE_RUNNING ; Check osKernelRunning
  192. BLT SVC_FuncCall ; Continue if kernel is not running
  193. LDR R0, [R0, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
  194. BLX IRQ_Disable ; Disable OS Tick interrupt
  195. SVC_FuncCall
  196. LDM SP, {R0-R3, R12} ; Reload R0-R3 and R12 from stack
  197. CPSIE i ; Re-enable interrupts
  198. BLX R12 ; Branch to SVC function
  199. CPSID i ; Disable interrupts
  200. STR R0, [SP] ; Store function return value
  201. LDR R0, =osRtxInfo
  202. LDR R1, [R0, #I_K_STATE_OFS] ; Load RTX5 kernel state
  203. CMP R1, #K_STATE_RUNNING ; Check osKernelRunning
  204. BLT SVC_ContextCheck ; Continue if kernel is not running
  205. LDR R0, [R0, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
  206. BLX IRQ_Enable ; Enable OS Tick interrupt
  207. SVC_ContextCheck
  208. BL osRtxContextSwitch ; Continue in context switcher
  209. LDR R0, =IRQ_NestLevel
  210. LDR R1, [R0]
  211. SUB R1, R1, #1 ; Decrement IRQ nesting level
  212. STR R1, [R0]
  213. CLREX ; Clear exclusive monitor
  214. POP {R0-R3, R12, LR} ; Restore stacked APCS registers
  215. RFEFD SP! ; Return from exception
  216. SVC_User
  217. PUSH {R4, R5}
  218. LDR R5,=osRtxUserSVC ; Load address of SVC table
  219. LDR R4,[R5] ; Load SVC maximum number
  220. CMP R12,R4 ; Check SVC number range
  221. BHI SVC_Done ; Branch if out of range
  222. LDR R12,[R5,R12,LSL #2] ; Load SVC Function Address
  223. BLX R12 ; Call SVC Function
  224. SVC_Done
  225. CLREX ; Clear exclusive monitor
  226. POP {R4, R5, R12, LR}
  227. RFEFD SP! ; Return from exception
  228. ENDP
  229. osRtxContextSwitch\
  230. PROC
  231. EXPORT osRtxContextSwitch
  232. IMPORT osRtxPendSV_Handler
  233. IMPORT osRtxInfo
  234. IMPORT IRQ_Disable
  235. IMPORT IRQ_Enable
  236. PUSH {LR}
  237. ; Check interrupt nesting level
  238. LDR R0, =IRQ_NestLevel
  239. LDR R1, [R0] ; Load IRQ nest level
  240. CMP R1, #1
  241. BNE osRtxContextExit ; Nesting interrupts, exit context switcher
  242. LDR R12, =osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.run
  243. LDM R12, {R0, R1} ; Load osRtxInfo.thread.run: curr & next
  244. LDR R2, =IRQ_PendSV ; Load address of IRQ_PendSV flag
  245. LDRB R3, [R2] ; Load PendSV flag
  246. CMP R0, R1 ; Check if context switch is required
  247. BNE osRtxContextCheck ; Not equal, check if context save required
  248. CMP R3, #1 ; Compare IRQ_PendSV value
  249. BNE osRtxContextExit ; No post processing (and no context switch requested)
  250. osRtxContextCheck
  251. STR R1, [R12] ; Store run.next as run.curr
  252. ; R0 = curr, R1 = next, R2 = &IRQ_PendSV, R3 = IRQ_PendSV, R12 = &osRtxInfo.thread.run
  253. PUSH {R1-R3, R12}
  254. CMP R0, #0 ; Is osRtxInfo.thread.run.curr == 0
  255. BEQ osRtxPostProcess ; Current deleted, skip context save
  256. osRtxContextSave
  257. MOV LR, R0 ; Move &osRtxInfo.thread.run.curr to LR
  258. MOV R0, SP ; Move SP_svc into R0
  259. ADD R0, R0, #20 ; Adjust SP_svc to R0 of the basic frame
  260. SUB SP, SP, #4
  261. STM SP, {SP}^ ; Save SP_usr to current stack
  262. POP {R1} ; Pop SP_usr into R1
  263. SUB R1, R1, #64 ; Adjust SP_usr to R4 of the basic frame
  264. STMIA R1!, {R4-R11} ; Save R4-R11 to user stack
  265. LDMIA R0!, {R4-R8} ; Load stacked R0-R3,R12 into R4-R8
  266. STMIA R1!, {R4-R8} ; Store them to user stack
  267. STM R1, {LR}^ ; Store LR_usr directly
  268. ADD R1, R1, #4 ; Adjust user sp to PC
  269. LDMIB R0!, {R5-R6} ; Load current PC, CPSR
  270. STMIA R1!, {R5-R6} ; Restore user PC and CPSR
  271. SUB R1, R1, #64 ; Adjust SP_usr to stacked R4
  272. ; Check if VFP state need to be saved
  273. MRC p15, 0, R2, c1, c0, 2 ; VFP/NEON access enabled? (CPACR)
  274. AND R2, R2, #0x00F00000
  275. CMP R2, #0x00F00000
  276. BNE osRtxContextSave1 ; Continue, no VFP
  277. VMRS R2, FPSCR
  278. STMDB R1!, {R2,R12} ; Push FPSCR, maintain 8-byte alignment
  279. VSTMDB R1!, {D0-D15} ; Save D0-D15
  280. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  281. VSTMDB R1!, {D16-D31} ; Save D16-D31
  282. ENDIF
  283. LDRB R2, [LR, #TCB_SP_FRAME] ; Load osRtxInfo.thread.run.curr frame info
  284. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  285. ORR R2, R2, #4 ; NEON state
  286. ELSE
  287. ORR R2, R2, #2 ; VFP state
  288. ENDIF
  289. STRB R2, [LR, #TCB_SP_FRAME] ; Store VFP/NEON state
  290. osRtxContextSave1
  291. STR R1, [LR, #TCB_SP_OFS] ; Store user sp to osRtxInfo.thread.run.curr
  292. osRtxPostProcess
  293. ; RTX IRQ post processing check
  294. POP {R8-R11} ; Pop R8 = run.next, R9 = &IRQ_PendSV, R10 = IRQ_PendSV, R11 = &osRtxInfo.thread.run
  295. CMP R10, #1 ; Compare PendSV value
  296. BNE osRtxContextRestore ; Skip post processing if not pending
  297. MOV R4, SP ; Move SP_svc into R4
  298. AND R4, R4, #4 ; Get stack adjustment to ensure 8-byte alignment
  299. SUB SP, SP, R4 ; Adjust stack
  300. ; Disable OS Tick
  301. LDR R5, =osRtxInfo ; Load address of osRtxInfo
  302. LDR R5, [R5, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
  303. MOV R0, R5 ; Set it as function parameter
  304. BLX IRQ_Disable ; Disable OS Tick interrupt
  305. MOV R6, #0 ; Set PendSV clear value
  306. B osRtxPendCheck
  307. osRtxPendExec
  308. STRB R6, [R9] ; Clear PendSV flag
  309. CPSIE i ; Re-enable interrupts
  310. BLX osRtxPendSV_Handler ; Post process pending objects
  311. CPSID i ; Disable interrupts
  312. osRtxPendCheck
  313. LDR R8, [R11, #4] ; Load osRtxInfo.thread.run.next
  314. STR R8, [R11] ; Store run.next as run.curr
  315. LDRB R0, [R9] ; Load PendSV flag
  316. CMP R0, #1 ; Compare PendSV value
  317. BEQ osRtxPendExec ; Branch to PendExec if PendSV is set
  318. ; Re-enable OS Tick
  319. MOV R0, R5 ; Restore irqn as function parameter
  320. BLX IRQ_Enable ; Enable OS Tick interrupt
  321. ADD SP, SP, R4 ; Restore stack adjustment
  322. osRtxContextRestore
  323. LDR LR, [R8, #TCB_SP_OFS] ; Load next osRtxThread_t.sp
  324. LDRB R2, [R8, #TCB_SP_FRAME] ; Load next osRtxThread_t.stack_frame
  325. ANDS R2, R2, #0x6 ; Check stack frame for VFP context
  326. MRC p15, 0, R2, c1, c0, 2 ; Read CPACR
  327. ANDEQ R2, R2, #0xFF0FFFFF ; VFP/NEON state not stacked, disable VFP/NEON
  328. ORRNE R2, R2, #0x00F00000 ; VFP/NEON state is stacked, enable VFP/NEON
  329. MCR p15, 0, R2, c1, c0, 2 ; Write CPACR
  330. BEQ osRtxContextRestore1 ; No VFP
  331. ISB ; Sync if VFP was enabled
  332. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  333. VLDMIA LR!, {D16-D31} ; Restore D16-D31
  334. ENDIF
  335. VLDMIA LR!, {D0-D15} ; Restore D0-D15
  336. LDR R2, [LR]
  337. VMSR FPSCR, R2 ; Restore FPSCR
  338. ADD LR, LR, #8 ; Adjust sp pointer to R4
  339. osRtxContextRestore1
  340. LDMIA LR!, {R4-R11} ; Restore R4-R11
  341. ADD R12, LR, #32 ; Adjust sp and save it into R12
  342. PUSH {R12} ; Push sp onto stack
  343. LDM SP, {SP}^ ; Restore SP_usr directly
  344. ADD SP, SP, #4 ; Adjust SP_svc
  345. LDMIA LR!, {R0-R3, R12} ; Load user registers R0-R3,R12
  346. STMIB SP!, {R0-R3, R12} ; Store them to SP_svc
  347. LDM LR, {LR}^ ; Restore LR_usr directly
  348. LDMIB LR!, {R0-R1} ; Load user registers PC,CPSR
  349. ADD SP, SP, #4
  350. STMIB SP!, {R0-R1} ; Store them to SP_svc
  351. SUB SP, SP, #32 ; Adjust SP_svc to stacked LR
  352. osRtxContextExit
  353. POP {PC} ; Return
  354. ENDP
  355. END