irq_ca.S 22 KB

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