1/* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2009-10-11 Bernard first version 9 * 2012-01-01 aozima support context switch load/store FPU register. 10 * 2013-06-18 aozima add restore MSP feature. 11 * 2013-06-23 aozima support lazy stack optimized. 12 * 2018-07-24 aozima enhancement hard fault exception handler. 13 */ 14 15/** 16 * @addtogroup cortex-m4 17 */ 18/*@{*/ 19 20#include <rtconfig.h> 21 22.cpu cortex-m4 23.syntax unified 24.thumb 25.text 26 27.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */ 28.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */ 29.equ NVIC_SYSPRI2, 0xE000ED20 /* system priority register (2) */ 30.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */ 31.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */ 32 33/* 34 * rt_base_t rt_hw_interrupt_disable(); 35 */ 36.global rt_hw_interrupt_disable 37.type rt_hw_interrupt_disable, %function 38rt_hw_interrupt_disable: 39 MRS r0, PRIMASK 40 CPSID I 41 BX LR 42 43/* 44 * void rt_hw_interrupt_enable(rt_base_t level); 45 */ 46.global rt_hw_interrupt_enable 47.type rt_hw_interrupt_enable, %function 48rt_hw_interrupt_enable: 49 MSR PRIMASK, r0 50 BX LR 51 52/* 53 * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); 54 * r0 --> from 55 * r1 --> to 56 */ 57.global rt_hw_context_switch_interrupt 58.type rt_hw_context_switch_interrupt, %function 59.global rt_hw_context_switch 60.type rt_hw_context_switch, %function 61 62rt_hw_context_switch_interrupt: 63rt_hw_context_switch: 64 /* set rt_thread_switch_interrupt_flag to 1 */ 65 LDR r2, =rt_thread_switch_interrupt_flag 66 LDR r3, [r2] 67 CMP r3, #1 68 BEQ _reswitch 69 MOV r3, #1 70 STR r3, [r2] 71 72 LDR r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */ 73 STR r0, [r2] 74 75_reswitch: 76 LDR r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */ 77 STR r1, [r2] 78 79 LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */ 80 LDR r1, =NVIC_PENDSVSET 81 STR r1, [r0] 82 BX LR 83 84/* r0 --> switch from thread stack 85 * r1 --> switch to thread stack 86 * psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack 87 */ 88.global PendSV_Handler 89.type PendSV_Handler, %function 90PendSV_Handler: 91 /* disable interrupt to protect context switch */ 92 MRS r2, PRIMASK 93 CPSID I 94 95 /* get rt_thread_switch_interrupt_flag */ 96 LDR r0, =rt_thread_switch_interrupt_flag /* r0 = &rt_thread_switch_interrupt_flag */ 97 LDR r1, [r0] /* r1 = *r1 */ 98 CMP r1, #0x00 /* compare r1 == 0x00 */ 99 BNE schedule 100 MSR PRIMASK, r2 /* if r1 == 0x00, do msr PRIMASK, r2 */ 101 BX lr /* if r1 == 0x00, do bx lr */ 102 103schedule: 104 PUSH {r2} /* store interrupt state */ 105 106 /* clear rt_thread_switch_interrupt_flag to 0 */ 107 MOV r1, #0x00 /* r1 = 0x00 */ 108 STR r1, [r0] /* *r0 = r1 */ 109 110 /* skip register save at the first time */ 111 LDR r0, =rt_interrupt_from_thread /* r0 = &rt_interrupt_from_thread */ 112 LDR r1, [r0] /* r1 = *r0 */ 113 CBZ r1, switch_to_thread /* if r1 == 0, goto switch_to_thread */ 114 115 /* Whether TrustZone thread stack exists */ 116 LDR r1, =rt_trustzone_current_context /* r1 = &rt_secure_current_context */ 117 LDR r1, [r1] /* r1 = *r1 */ 118 CBZ r1, contex_ns_store /* if r1 == 0, goto contex_ns_store */ 119 120 /*call TrustZone fun, Save TrustZone stack */ 121 STMFD sp!, {r0-r1, lr} /* push register */ 122 MOV r0, r1 /* r0 = rt_secure_current_context */ 123 BL rt_trustzone_context_store /* call TrustZone store fun */ 124 LDMFD sp!, {r0-r1, lr} /* pop register */ 125 126 /* check break from TrustZone */ 127 MOV r2, lr /* r2 = lr */ 128 TST r2, #0x40 /* if EXC_RETURN[6] is 1, TrustZone stack was used */ 129 BEQ contex_ns_store /* if r2 & 0x40 == 0, goto contex_ns_store */ 130 131 /* push PSPLIM CONTROL PSP LR current_context to stack */ 132 MRS r3, psplim /* r3 = psplim */ 133 MRS r4, control /* r4 = control */ 134 MRS r5, psp /* r5 = psp */ 135 STMFD r5!, {r1-r4} /* push to thread stack */ 136 137 /* update from thread stack pointer */ 138 LDR r0, [r0] /* r0 = rt_thread_switch_interrupt_flag */ 139 STR r5, [r0] /* *r0 = r5 */ 140 b switch_to_thread /* goto switch_to_thread */ 141 142contex_ns_store: 143 144 MRS r1, psp /* get from thread stack pointer */ 145 146#if defined (__VFP_FP__) && !defined(__SOFTFP__) 147 TST lr, #0x10 /* if(!EXC_RETURN[4]) */ 148 IT EQ 149 VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */ 150#endif 151 152 STMFD r1!, {r4 - r11} /* push r4 - r11 register */ 153 154 LDR r2, =rt_trustzone_current_context /* r2 = &rt_secure_current_context */ 155 LDR r2, [r2] /* r2 = *r2 */ 156 MOV r3, lr /* r3 = lr */ 157 MRS r4, psplim /* r4 = psplim */ 158 MRS r5, control /* r5 = control */ 159 STMFD r1!, {r2-r5} /* push to thread stack */ 160 161 LDR r0, [r0] 162 STR r1, [r0] /* update from thread stack pointer */ 163 164switch_to_thread: 165 LDR r1, =rt_interrupt_to_thread 166 LDR r1, [r1] 167 LDR r1, [r1] /* load thread stack pointer */ 168 169 /* update current TrustZone context */ 170 LDMFD r1!, {r2-r5} /* pop thread stack */ 171 MSR psplim, r4 /* psplim = r4 */ 172 MSR control, r5 /* control = r5 */ 173 MOV lr, r3 /* lr = r3 */ 174 LDR r6, =rt_trustzone_current_context /* r6 = &rt_secure_current_context */ 175 STR r2, [r6] /* *r6 = r2 */ 176 MOV r0, r2 /* r0 = r2 */ 177 178 /* Whether TrustZone thread stack exists */ 179 CBZ r0, contex_ns_load /* if r0 == 0, goto contex_ns_load */ 180 PUSH {r1, r3} /* push lr, thread_stack */ 181 BL rt_trustzone_context_load /* call TrustZone load fun */ 182 POP {r1, r3} /* pop lr, thread_stack */ 183 MOV lr, r3 /* lr = r1 */ 184 TST r3, #0x40 /* if EXC_RETURN[6] is 1, TrustZone stack was used */ 185 BEQ contex_ns_load /* if r1 & 0x40 == 0, goto contex_ns_load */ 186 B pendsv_exit 187 188contex_ns_load: 189 LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */ 190 191#if defined (__VFP_FP__) && !defined(__SOFTFP__) 192 TST lr, #0x10 /* if(!EXC_RETURN[4]) */ 193 IT EQ 194 VLDMIAEQ r1!, {d8 - d15} /* pop FPU register s16~s31 */ 195#endif 196 197#if defined (RT_USING_MEM_PROTECTION) 198 PUSH {r0-r3, r12, lr} 199 BL rt_thread_self 200 BL rt_hw_mpu_table_switch 201 POP {r0-r3, r12, lr} 202#endif 203 204pendsv_exit: 205 MSR psp, r1 /* update stack pointer */ 206 /* restore interrupt */ 207 POP {r2} 208 MSR PRIMASK, r2 209 210 BX lr 211 212/* 213 * void rt_hw_context_switch_to(rt_uint32 to); 214 * r0 --> to 215 */ 216.global rt_hw_context_switch_to 217.type rt_hw_context_switch_to, %function 218rt_hw_context_switch_to: 219 LDR r1, =rt_interrupt_to_thread 220 STR r0, [r1] 221 222#if defined (__VFP_FP__) && !defined(__SOFTFP__) 223 /* CLEAR CONTROL.FPCA */ 224 MRS r2, CONTROL /* read */ 225 BIC r2, #0x04 /* modify */ 226 MSR CONTROL, r2 /* write-back */ 227#endif 228 229 /* set from thread to 0 */ 230 LDR r1, =rt_interrupt_from_thread 231 MOV r0, #0x0 232 STR r0, [r1] 233 234 /* set interrupt flag to 1 */ 235 LDR r1, =rt_thread_switch_interrupt_flag 236 MOV r0, #1 237 STR r0, [r1] 238 239 /* set the PendSV and SysTick exception priority */ 240 LDR r0, =NVIC_SYSPRI2 241 LDR r1, =NVIC_PENDSV_PRI 242 LDR.W r2, [r0,#0x00] /* read */ 243 ORR r1,r1,r2 /* modify */ 244 STR r1, [r0] /* write-back */ 245 246 LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */ 247 LDR r1, =NVIC_PENDSVSET 248 STR r1, [r0] 249 250 /* restore MSP */ 251 LDR r0, =SCB_VTOR 252 LDR r0, [r0] 253 LDR r0, [r0] 254 NOP 255 MSR msp, r0 256 257 /* enable interrupts at processor level */ 258 CPSIE F 259 CPSIE I 260 261 /* ensure PendSV exception taken place before subsequent operation */ 262 DSB 263 ISB 264 265 /* never reach here! */ 266 267/* compatible with old version */ 268.global rt_hw_interrupt_thread_switch 269.type rt_hw_interrupt_thread_switch, %function 270rt_hw_interrupt_thread_switch: 271 BX lr 272 NOP 273 274.global HardFault_Handler 275.type HardFault_Handler, %function 276HardFault_Handler: 277 /* get current context */ 278 MRS r0, msp /* get fault context from handler. */ 279 TST lr, #0x04 /* if(!EXC_RETURN[2]) */ 280 BEQ get_sp_done 281 MRS r0, psp /* get fault context from thread. */ 282get_sp_done: 283 284#if defined (__VFP_FP__) && !defined(__SOFTFP__) 285 TST lr, #0x10 /* if(!EXC_RETURN[4]) */ 286 IT EQ 287 VSTMDBEQ r0!, {d8 - d15} /* push FPU register s16~s31 */ 288#endif 289 290 STMFD r0!, {r4 - r11} /* push r4 - r11 register */ 291 292 LDR r2, =rt_trustzone_current_context /* r2 = &rt_secure_current_context */ 293 LDR r2, [r2] /* r2 = *r2 */ 294 MOV r3, lr /* r3 = lr */ 295 MRS r4, psplim /* r4 = psplim */ 296 MRS r5, control /* r5 = control */ 297 STMFD r0!, {r2-r5} /* push to thread stack */ 298 299 STMFD r0!, {lr} /* push exec_return register */ 300 301 TST lr, #0x04 /* if(!EXC_RETURN[2]) */ 302 BEQ update_msp 303 MSR psp, r0 /* update stack pointer to PSP. */ 304 B update_done 305update_msp: 306 MSR msp, r0 /* update stack pointer to MSP. */ 307update_done: 308 309 PUSH {LR} 310 BL rt_hw_hard_fault_exception 311 POP {LR} 312 313 ORR lr, lr, #0x04 314 BX lr 315