irq_ca.s 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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. 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}
  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. POP {R0-R3}
  197. LDR R12, [SP] ; Reload R12 from stack
  198. CPSIE i ; Re-enable interrupts
  199. BLX R12 ; Branch to SVC function
  200. CPSID i ; Disable interrupts
  201. SUB SP, SP, #4
  202. STM SP, {SP}^ ; Store SP_usr onto stack
  203. POP {R12} ; Pop SP_usr into R12
  204. SUB R12, R12, #16 ; Adjust pointer to SP_usr
  205. LDMDB R12, {R2,R3} ; Load return values from SVC function
  206. PUSH {R0-R3} ; Push return values to stack
  207. LDR R0, =osRtxInfo
  208. LDR R1, [R0, #I_K_STATE_OFS] ; Load RTX5 kernel state
  209. CMP R1, #K_STATE_RUNNING ; Check osKernelRunning
  210. BLT SVC_ContextCheck ; Continue if kernel is not running
  211. LDR R0, [R0, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
  212. BLX IRQ_Enable ; Enable OS Tick interrupt
  213. SVC_ContextCheck
  214. BL osRtxContextSwitch ; Continue in context switcher
  215. LDR R0, =IRQ_NestLevel
  216. LDR R1, [R0]
  217. SUB R1, R1, #1 ; Decrement IRQ nesting level
  218. STR R1, [R0]
  219. CLREX ; Clear exclusive monitor
  220. POP {R0-R3, R12, LR} ; Restore stacked APCS registers
  221. RFEFD SP! ; Return from exception
  222. SVC_User
  223. PUSH {R4, R5}
  224. LDR R5,=osRtxUserSVC ; Load address of SVC table
  225. LDR R4,[R5] ; Load SVC maximum number
  226. CMP R12,R4 ; Check SVC number range
  227. BHI SVC_Done ; Branch if out of range
  228. LDR R12,[R5,R12,LSL #2] ; Load SVC Function Address
  229. BLX R12 ; Call SVC Function
  230. SVC_Done
  231. CLREX ; Clear exclusive monitor
  232. POP {R4, R5, R12, LR}
  233. RFEFD SP! ; Return from exception
  234. ENDP
  235. osRtxContextSwitch\
  236. PROC
  237. EXPORT osRtxContextSwitch
  238. IMPORT osRtxPendSV_Handler
  239. IMPORT osRtxInfo
  240. IMPORT IRQ_Disable
  241. IMPORT IRQ_Enable
  242. PUSH {LR}
  243. ; Check interrupt nesting level
  244. LDR R0, =IRQ_NestLevel
  245. LDR R1, [R0] ; Load IRQ nest level
  246. CMP R1, #1
  247. BNE osRtxContextExit ; Nesting interrupts, exit context switcher
  248. LDR R12, =osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.run
  249. LDM R12, {R0, R1} ; Load osRtxInfo.thread.run: curr & next
  250. LDR R2, =IRQ_PendSV ; Load address of IRQ_PendSV flag
  251. LDRB R3, [R2] ; Load PendSV flag
  252. CMP R0, R1 ; Check if context switch is required
  253. BNE osRtxContextCheck ; Not equal, check if context save required
  254. CMP R3, #1 ; Compare IRQ_PendSV value
  255. BNE osRtxContextExit ; No post processing (and no context switch requested)
  256. osRtxContextCheck
  257. STR R1, [R12] ; Store run.next as run.curr
  258. ; R0 = curr, R1 = next, R2 = &IRQ_PendSV, R3 = IRQ_PendSV, R12 = &osRtxInfo.thread.run
  259. PUSH {R1-R3, R12}
  260. CMP R0, #0 ; Is osRtxInfo.thread.run.curr == 0
  261. BEQ osRtxPostProcess ; Current deleted, skip context save
  262. osRtxContextSave
  263. MOV LR, R0 ; Move &osRtxInfo.thread.run.curr to LR
  264. MOV R0, SP ; Move SP_svc into R0
  265. ADD R0, R0, #20 ; Adjust SP_svc to R0 of the basic frame
  266. SUB SP, SP, #4
  267. STM SP, {SP}^ ; Save SP_usr to current stack
  268. POP {R1} ; Pop SP_usr into R1
  269. SUB R1, R1, #64 ; Adjust SP_usr to R4 of the basic frame
  270. STMIA R1!, {R4-R11} ; Save R4-R11 to user stack
  271. LDMIA R0!, {R4-R8} ; Load stacked R0-R3,R12 into R4-R8
  272. STMIA R1!, {R4-R8} ; Store them to user stack
  273. STM R1, {LR}^ ; Store LR_usr directly
  274. ADD R1, R1, #4 ; Adjust user sp to PC
  275. LDMIB R0!, {R5-R6} ; Load current PC, CPSR
  276. STMIA R1!, {R5-R6} ; Restore user PC and CPSR
  277. SUB R1, R1, #64 ; Adjust SP_usr to stacked R4
  278. ; Check if VFP state need to be saved
  279. MRC p15, 0, R2, c1, c0, 2 ; VFP/NEON access enabled? (CPACR)
  280. AND R2, R2, #0x00F00000
  281. CMP R2, #0x00F00000
  282. BNE osRtxContextSave1 ; Continue, no VFP
  283. VMRS R2, FPSCR
  284. STMDB R1!, {R2,R12} ; Push FPSCR, maintain 8-byte alignment
  285. VSTMDB R1!, {D0-D15} ; Save D0-D15
  286. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  287. VSTMDB R1!, {D16-D31} ; Save D16-D31
  288. ENDIF
  289. LDRB R2, [LR, #TCB_SP_FRAME] ; Load osRtxInfo.thread.run.curr frame info
  290. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  291. ORR R2, R2, #4 ; NEON state
  292. ELSE
  293. ORR R2, R2, #2 ; VFP state
  294. ENDIF
  295. STRB R2, [LR, #TCB_SP_FRAME] ; Store VFP/NEON state
  296. osRtxContextSave1
  297. STR R1, [LR, #TCB_SP_OFS] ; Store user sp to osRtxInfo.thread.run.curr
  298. osRtxPostProcess
  299. ; RTX IRQ post processing check
  300. POP {R8-R11} ; Pop R8 = run.next, R9 = &IRQ_PendSV, R10 = IRQ_PendSV, R11 = &osRtxInfo.thread.run
  301. CMP R10, #1 ; Compare PendSV value
  302. BNE osRtxContextRestore ; Skip post processing if not pending
  303. MOV R4, SP ; Move SP_svc into R4
  304. AND R4, R4, #4 ; Get stack adjustment to ensure 8-byte alignment
  305. SUB SP, SP, R4 ; Adjust stack
  306. ; Disable OS Tick
  307. LDR R5, =osRtxInfo ; Load address of osRtxInfo
  308. LDR R5, [R5, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
  309. MOV R0, R5 ; Set it as function parameter
  310. BLX IRQ_Disable ; Disable OS Tick interrupt
  311. MOV R6, #0 ; Set PendSV clear value
  312. B osRtxPendCheck
  313. osRtxPendExec
  314. STRB R6, [R9] ; Clear PendSV flag
  315. CPSIE i ; Re-enable interrupts
  316. BLX osRtxPendSV_Handler ; Post process pending objects
  317. CPSID i ; Disable interrupts
  318. osRtxPendCheck
  319. LDR R8, [R11, #4] ; Load osRtxInfo.thread.run.next
  320. STR R8, [R11] ; Store run.next as run.curr
  321. LDRB R0, [R9] ; Load PendSV flag
  322. CMP R0, #1 ; Compare PendSV value
  323. BEQ osRtxPendExec ; Branch to PendExec if PendSV is set
  324. ; Re-enable OS Tick
  325. MOV R0, R5 ; Restore irqn as function parameter
  326. BLX IRQ_Enable ; Enable OS Tick interrupt
  327. ADD SP, SP, R4 ; Restore stack adjustment
  328. osRtxContextRestore
  329. LDR LR, [R8, #TCB_SP_OFS] ; Load next osRtxThread_t.sp
  330. LDRB R2, [R8, #TCB_SP_FRAME] ; Load next osRtxThread_t.stack_frame
  331. ANDS R2, R2, #0x6 ; Check stack frame for VFP context
  332. MRC p15, 0, R2, c1, c0, 2 ; Read CPACR
  333. ANDEQ R2, R2, #0xFF0FFFFF ; VFP/NEON state not stacked, disable VFP/NEON
  334. ORRNE R2, R2, #0x00F00000 ; VFP/NEON state is stacked, enable VFP/NEON
  335. MCR p15, 0, R2, c1, c0, 2 ; Write CPACR
  336. BEQ osRtxContextRestore1 ; No VFP
  337. ISB ; Sync if VFP was enabled
  338. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  339. VLDMIA LR!, {D16-D31} ; Restore D16-D31
  340. ENDIF
  341. VLDMIA LR!, {D0-D15} ; Restore D0-D15
  342. LDR R2, [LR]
  343. VMSR FPSCR, R2 ; Restore FPSCR
  344. ADD LR, LR, #8 ; Adjust sp pointer to R4
  345. osRtxContextRestore1
  346. LDMIA LR!, {R4-R11} ; Restore R4-R11
  347. ADD R12, LR, #32 ; Adjust sp and save it into R12
  348. PUSH {R12} ; Push sp onto stack
  349. LDM SP, {SP}^ ; Restore SP_usr directly
  350. ADD SP, SP, #4 ; Adjust SP_svc
  351. LDMIA LR!, {R0-R3, R12} ; Load user registers R0-R3,R12
  352. STMIB SP!, {R0-R3, R12} ; Store them to SP_svc
  353. LDM LR, {LR}^ ; Restore LR_usr directly
  354. LDMIB LR!, {R0-R1} ; Load user registers PC,CPSR
  355. ADD SP, SP, #4
  356. STMIB SP!, {R0-R1} ; Store them to SP_svc
  357. SUB SP, SP, #32 ; Adjust SP_svc to stacked LR
  358. osRtxContextExit
  359. POP {PC} ; Return
  360. ENDP
  361. END