irq_armv7a.s 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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. 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. TCB_ZONE_OFS EQU 68 ; osRtxThread_t.zone offset
  38. PRESERVE8
  39. ARM
  40. AREA |.constdata|, DATA, READONLY
  41. EXPORT irqRtxLib
  42. irqRtxLib DCB 0 ; Non weak library reference
  43. AREA |.data|, DATA, READWRITE
  44. EXPORT SVC_Active
  45. EXPORT IRQ_PendSV
  46. IRQ_NestLevel DCD 0 ; IRQ nesting level counter
  47. SVC_Active DCB 0 ; SVC Handler Active
  48. IRQ_PendSV DCB 0 ; Pending SVC flag
  49. AREA |.text|, CODE, READONLY
  50. Undef_Handler\
  51. PROC
  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. ENDP
  90. PAbt_Handler\
  91. PROC
  92. EXPORT PAbt_Handler
  93. IMPORT CPAbtHandler
  94. SUB LR, LR, #4 ; Pre-adjust LR
  95. SRSFD SP!, #MODE_ABT ; Save LR and SPRS to ABT mode stack
  96. PUSH {R0-R4, R12} ; Save APCS corruptible registers to ABT mode stack
  97. MRC p15, 0, R0, c5, c0, 1 ; IFSR
  98. MRC p15, 0, R1, c6, c0, 2 ; IFAR
  99. MOV R2, LR ; Set LR to third argument
  100. AND R12, SP, #4 ; Ensure stack is 8-byte aligned
  101. SUB SP, SP, R12 ; Adjust stack
  102. PUSH {R12, LR} ; Store stack adjustment and dummy LR
  103. BL CPAbtHandler
  104. POP {R12, LR} ; Get stack adjustment & discard dummy LR
  105. ADD SP, SP, R12 ; Unadjust stack
  106. CLREX ; Clear exclusive monitor
  107. POP {R0-R4, R12} ; Restore stack APCS registers
  108. RFEFD SP! ; Return from exception
  109. ENDP
  110. DAbt_Handler\
  111. PROC
  112. EXPORT DAbt_Handler
  113. IMPORT CDAbtHandler
  114. SUB LR, LR, #8 ; Pre-adjust LR
  115. SRSFD SP!, #MODE_ABT ; Save LR and SPRS to ABT mode stack
  116. PUSH {R0-R4, R12} ; Save APCS corruptible registers to ABT mode stack
  117. MRC p15, 0, R0, c5, c0, 0 ; DFSR
  118. MRC p15, 0, R1, c6, c0, 0 ; DFAR
  119. MOV R2, LR ; Set LR to third argument
  120. AND R12, SP, #4 ; Ensure stack is 8-byte aligned
  121. SUB SP, SP, R12 ; Adjust stack
  122. PUSH {R12, LR} ; Store stack adjustment and dummy LR
  123. BL CDAbtHandler
  124. POP {R12, LR} ; Get stack adjustment & discard dummy LR
  125. ADD SP, SP, R12 ; Unadjust stack
  126. CLREX ; Clear exclusive monitor
  127. POP {R0-R4, R12} ; Restore stacked APCS registers
  128. RFEFD SP! ; Return from exception
  129. ENDP
  130. IRQ_Handler\
  131. PROC
  132. EXPORT IRQ_Handler
  133. IMPORT IRQ_GetActiveIRQ
  134. IMPORT IRQ_GetHandler
  135. IMPORT IRQ_EndOfInterrupt
  136. SUB LR, LR, #4 ; Pre-adjust LR
  137. SRSFD SP!, #MODE_SVC ; Save LR_irq and SPSR_irq on to the SVC stack
  138. CPS #MODE_SVC ; Change to SVC mode
  139. PUSH {R0-R3, R12, LR} ; Save APCS corruptible registers
  140. LDR R0, =IRQ_NestLevel
  141. LDR R1, [R0]
  142. ADD R1, R1, #1 ; Increment IRQ nesting level
  143. STR R1, [R0]
  144. MOV R3, SP ; Move SP into R3
  145. AND R3, R3, #4 ; Get stack adjustment to ensure 8-byte alignment
  146. SUB SP, SP, R3 ; Adjust stack
  147. PUSH {R3, R4} ; Store stack adjustment(R3) and user data(R4)
  148. BLX IRQ_GetActiveIRQ ; Retrieve interrupt ID into R0
  149. MOV R4, R0 ; Move interrupt ID to R4
  150. BLX IRQ_GetHandler ; Retrieve interrupt handler address for current ID
  151. CMP R0, #0 ; Check if handler address is 0
  152. BEQ IRQ_End ; If 0, end interrupt and return
  153. CPSIE i ; Re-enable interrupts
  154. BLX R0 ; Call IRQ handler
  155. CPSID i ; Disable interrupts
  156. IRQ_End
  157. MOV R0, R4 ; Move interrupt ID to R0
  158. BLX IRQ_EndOfInterrupt ; Signal end of interrupt
  159. POP {R3, R4} ; Restore stack adjustment(R3) and user data(R4)
  160. ADD SP, SP, R3 ; Unadjust stack
  161. BL osRtxContextSwitch ; Continue in context switcher
  162. LDR R0, =IRQ_NestLevel
  163. LDR R1, [R0]
  164. SUBS R1, R1, #1 ; Decrement IRQ nesting level
  165. STR R1, [R0]
  166. CLREX ; Clear exclusive monitor for interrupted code
  167. POP {R0-R3, R12, LR} ; Restore stacked APCS registers
  168. RFEFD SP! ; Return from IRQ handler
  169. ENDP
  170. SVC_Handler\
  171. PROC
  172. EXPORT SVC_Handler
  173. IMPORT IRQ_Disable
  174. IMPORT IRQ_Enable
  175. IMPORT osRtxUserSVC
  176. IMPORT osRtxInfo
  177. SRSFD SP!, #MODE_SVC ; Store SPSR_svc and LR_svc onto SVC stack
  178. PUSH {R12, LR}
  179. MRS R12, SPSR ; Load SPSR
  180. TST R12, #CPSR_BIT_T ; Thumb bit set?
  181. LDRHNE R12, [LR,#-2] ; Thumb: load halfword
  182. BICNE R12, R12, #0xFF00 ; extract SVC number
  183. LDREQ R12, [LR,#-4] ; ARM: load word
  184. BICEQ R12, R12, #0xFF000000 ; extract SVC number
  185. CMP R12, #0 ; Compare SVC number
  186. BNE SVC_User ; Branch if User SVC
  187. PUSH {R0-R3} ; Push arguments to stack
  188. LDR R0, =SVC_Active
  189. MOV R1, #1
  190. STRB R1, [R0] ; Set SVC Handler Active
  191. LDR R0, =IRQ_NestLevel
  192. LDR R1, [R0]
  193. ADD R1, R1, #1 ; Increment IRQ nesting level
  194. STR R1, [R0]
  195. LDR R0, =osRtxInfo
  196. LDR R1, [R0, #I_K_STATE_OFS] ; Load RTX5 kernel state
  197. CMP R1, #K_STATE_RUNNING ; Check osKernelRunning
  198. BLT SVC_FuncCall ; Continue if kernel is not running
  199. LDR R0, [R0, #I_TICK_IRQN_OFS] ; Load OS Tick irqn
  200. BLX IRQ_Disable ; Disable OS Tick interrupt
  201. SVC_FuncCall
  202. LDM SP, {R0-R3, R12} ; Reload R0-R3 and R12 from stack
  203. CPSIE i ; Re-enable interrupts
  204. BLX R12 ; Branch to SVC function
  205. CPSID i ; Disable interrupts
  206. STR R0, [SP] ; Store function return value
  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. LDR R0, =SVC_Active
  220. MOV R1, #0
  221. STRB R1, [R0] ; Clear SVC Handler Active
  222. CLREX ; Clear exclusive monitor
  223. POP {R0-R3, R12, LR} ; Restore stacked APCS registers
  224. RFEFD SP! ; Return from exception
  225. SVC_User
  226. PUSH {R4, R5}
  227. LDR R5,=osRtxUserSVC ; Load address of SVC table
  228. LDR R4,[R5] ; Load SVC maximum number
  229. CMP R12,R4 ; Check SVC number range
  230. BHI SVC_Done ; Branch if out of range
  231. LDR R12,[R5,R12,LSL #2] ; Load SVC Function Address
  232. BLX R12 ; Call SVC Function
  233. SVC_Done
  234. CLREX ; Clear exclusive monitor
  235. POP {R4, R5, R12, LR}
  236. RFEFD SP! ; Return from exception
  237. ENDP
  238. osRtxContextSwitch\
  239. PROC
  240. EXPORT osRtxContextSwitch
  241. IMPORT osRtxPendSV_Handler
  242. IMPORT osRtxInfo
  243. IF :DEF:RTX_EXECUTION_ZONE
  244. IMPORT osZoneSetup_Callback
  245. ENDIF
  246. IMPORT IRQ_Disable
  247. IMPORT IRQ_Enable
  248. PUSH {LR}
  249. ; Check interrupt nesting level
  250. LDR R0, =IRQ_NestLevel
  251. LDR R1, [R0] ; Load IRQ nest level
  252. CMP R1, #1
  253. BNE osRtxContextExit ; Nesting interrupts, exit context switcher
  254. LDR R12, =osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.run
  255. LDM R12, {R0, R1} ; Load osRtxInfo.thread.run: curr & next
  256. LDR R2, =IRQ_PendSV ; Load address of IRQ_PendSV flag
  257. LDRB R3, [R2] ; Load PendSV flag
  258. CMP R0, R1 ; Check if context switch is required
  259. BNE osRtxContextCheck ; Not equal, check if context save required
  260. CMP R3, #1 ; Compare IRQ_PendSV value
  261. BNE osRtxContextExit ; No post processing (and no context switch requested)
  262. osRtxContextCheck
  263. STR R1, [R12] ; Store run.next as run.curr
  264. ; R0 = curr, R1 = next, R2 = &IRQ_PendSV, R12 = &osRtxInfo.thread.run
  265. PUSH {R0-R2, R12}
  266. CMP R0, #0 ; Is osRtxInfo.thread.run.curr == 0
  267. BEQ osRtxPostProcess ; Current deleted, skip context save
  268. osRtxContextSave
  269. MOV LR, R0 ; Move &osRtxInfo.thread.run.curr to LR
  270. MOV R0, SP ; Move SP_svc into R0
  271. ADD R0, R0, #20 ; Adjust SP_svc to R0 of the basic frame
  272. SUB SP, SP, #4
  273. STM SP, {SP}^ ; Save SP_usr to current stack
  274. POP {R1} ; Pop SP_usr into R1
  275. SUB R1, R1, #64 ; Adjust SP_usr to R4 of the basic frame
  276. STMIA R1!, {R4-R11} ; Save R4-R11 to user stack
  277. LDMIA R0!, {R4-R8} ; Load stacked R0-R3,R12 into R4-R8
  278. STMIA R1!, {R4-R8} ; Store them to user stack
  279. STM R1, {LR}^ ; Store LR_usr directly
  280. ADD R1, R1, #4 ; Adjust user sp to PC
  281. LDMIB R0!, {R5-R6} ; Load stacked PC, CPSR
  282. STMIA R1!, {R5-R6} ; Store them to user stack
  283. SUB R1, R1, #64 ; Adjust SP_usr to stacked R4
  284. ; Check if VFP state need to be saved
  285. MRC p15, 0, R2, c1, c0, 2 ; VFP/NEON access enabled? (CPACR)
  286. AND R2, R2, #0x00F00000
  287. CMP R2, #0x00F00000
  288. BNE osRtxContextSave1 ; Continue, no VFP
  289. VMRS R2, FPSCR
  290. STMDB R1!, {R2,R12} ; Push FPSCR, maintain 8-byte alignment
  291. VSTMDB R1!, {D0-D15} ; Save D0-D15
  292. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  293. VSTMDB R1!, {D16-D31} ; Save D16-D31
  294. ENDIF
  295. LDRB R2, [LR, #TCB_SP_FRAME] ; Load osRtxInfo.thread.run.curr frame info
  296. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  297. ORR R2, R2, #4 ; NEON state
  298. ELSE
  299. ORR R2, R2, #2 ; VFP state
  300. ENDIF
  301. STRB R2, [LR, #TCB_SP_FRAME] ; Store VFP/NEON state
  302. osRtxContextSave1
  303. STR R1, [LR, #TCB_SP_OFS] ; Store user sp to osRtxInfo.thread.run.curr
  304. osRtxPostProcess
  305. ; RTX IRQ post processing check
  306. POP {R8-R11} ; Pop R8 = curr, R9 = next, R10 = &IRQ_PendSV, R11 = &osRtxInfo.thread.run
  307. LDRB R0, [R10] ; Load PendSV flag
  308. CMP R0, #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, [R10] ; 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 R9, [R11, #4] ; Load osRtxInfo.thread.run.next
  327. STR R9, [R11] ; Store run.next as run.curr
  328. LDRB R0, [R10] ; 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. IF :DEF:RTX_EXECUTION_ZONE
  337. LDRB R0, [R9, #TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.next: zone
  338. CMP R8, #0
  339. BEQ osRtxZoneSetup ; Branch if running thread is deleted
  340. LDRB R1, [R8, #TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.curr: zone
  341. CMP R0, R1 ; Check if next:zone == curr:zone
  342. BEQ osRtxContextRestoreFrame ; Branch if zone has not changed
  343. osRtxZoneSetup
  344. BL osZoneSetup_Callback ; Setup zone for next thread
  345. ENDIF
  346. osRtxContextRestoreFrame
  347. LDR LR, [R8, #TCB_SP_OFS] ; Load next osRtxThread_t.sp
  348. LDRB R2, [R8, #TCB_SP_FRAME] ; Load next osRtxThread_t.stack_frame
  349. ANDS R2, R2, #0x6 ; Check stack frame for VFP context
  350. MRC p15, 0, R2, c1, c0, 2 ; Read CPACR
  351. ANDEQ R2, R2, #0xFF0FFFFF ; VFP/NEON state not stacked, disable VFP/NEON
  352. ORRNE R2, R2, #0x00F00000 ; VFP/NEON state is stacked, enable VFP/NEON
  353. MCR p15, 0, R2, c1, c0, 2 ; Write CPACR
  354. BEQ osRtxContextRestore1 ; No VFP
  355. ISB ; Sync if VFP was enabled
  356. IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
  357. VLDMIA LR!, {D16-D31} ; Restore D16-D31
  358. ENDIF
  359. VLDMIA LR!, {D0-D15} ; Restore D0-D15
  360. LDR R2, [LR]
  361. VMSR FPSCR, R2 ; Restore FPSCR
  362. ADD LR, LR, #8 ; Adjust sp pointer to R4
  363. osRtxContextRestore1
  364. LDMIA LR!, {R4-R11} ; Restore R4-R11
  365. ADD R12, LR, #32 ; Adjust sp and save it into R12
  366. PUSH {R12} ; Push sp onto stack
  367. LDM SP, {SP}^ ; Restore SP_usr directly
  368. ADD SP, SP, #4 ; Adjust SP_svc
  369. LDMIA LR!, {R0-R3, R12} ; Load user registers R0-R3,R12
  370. STMIB SP!, {R0-R3, R12} ; Store them to SP_svc
  371. LDM LR, {LR}^ ; Restore LR_usr directly
  372. LDMIB LR!, {R0-R1} ; Load user registers PC,CPSR
  373. ADD SP, SP, #4
  374. STMIB SP!, {R0-R1} ; Store them to SP_svc
  375. SUB SP, SP, #32 ; Adjust SP_svc to stacked LR
  376. osRtxContextExit
  377. POP {PC} ; Return
  378. ENDP
  379. END