irq_ca.s 21 KB

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