irq_armv7a.s 22 KB

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