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-01-17 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 20SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register 21NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register 22NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2) 23NVIC_PENDSV_PRI EQU 0x00FF0000 ; PendSV priority value (lowest) 24NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception 25 26 AREA |.text|, CODE, READONLY, ALIGN=2 27 THUMB 28 REQUIRE8 29 PRESERVE8 30 31 IMPORT rt_thread_switch_interrupt_flag 32 IMPORT rt_interrupt_from_thread 33 IMPORT rt_interrupt_to_thread 34 35;/* 36; * rt_base_t rt_hw_interrupt_disable(); 37; */ 38rt_hw_interrupt_disable PROC 39 EXPORT rt_hw_interrupt_disable 40 MRS r0, PRIMASK 41 CPSID I 42 BX LR 43 ENDP 44 45;/* 46; * void rt_hw_interrupt_enable(rt_base_t level); 47; */ 48rt_hw_interrupt_enable PROC 49 EXPORT rt_hw_interrupt_enable 50 MSR PRIMASK, r0 51 BX LR 52 ENDP 53 54;/* 55; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); 56; * r0 --> from 57; * r1 --> to 58; */ 59rt_hw_context_switch_interrupt 60 EXPORT rt_hw_context_switch_interrupt 61rt_hw_context_switch PROC 62 EXPORT rt_hw_context_switch 63 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 ENDP 84 85; r0 --> switch from thread stack 86; r1 --> switch to thread stack 87; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack 88PendSV_Handler PROC 89 EXPORT PendSV_Handler 90 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 97 LDR r1, [r0] 98 CBZ r1, pendsv_exit ; pendsv already handled 99 100 ; clear rt_thread_switch_interrupt_flag to 0 101 MOV r1, #0x00 102 STR r1, [r0] 103 104 LDR r0, =rt_interrupt_from_thread 105 LDR r1, [r0] 106 CBZ r1, switch_to_thread ; skip register save at the first time 107 108 MRS r1, psp ; get from thread stack pointer 109 110 IF {FPU} != "SoftVFP" 111 TST lr, #0x10 ; if(!EXC_RETURN[4]) 112 VSTMFDEQ r1!, {d8 - d15} ; push FPU register s16~s31 113 ENDIF 114 115 STMFD r1!, {r4 - r11} ; push r4 - r11 register 116 117 IF {FPU} != "SoftVFP" 118 MOV r4, #0x00 ; flag = 0 119 120 TST lr, #0x10 ; if(!EXC_RETURN[4]) 121 MOVEQ r4, #0x01 ; flag = 1 122 123 STMFD r1!, {r4} ; push flag 124 ENDIF 125 126 LDR r0, [r0] 127 STR r1, [r0] ; update from thread stack pointer 128 129switch_to_thread 130 LDR r1, =rt_interrupt_to_thread 131 LDR r1, [r1] 132 LDR r1, [r1] ; load thread stack pointer 133 134 IF {FPU} != "SoftVFP" 135 LDMFD r1!, {r3} ; pop flag 136 ENDIF 137 138 LDMFD r1!, {r4 - r11} ; pop r4 - r11 register 139 140 IF {FPU} != "SoftVFP" 141 CMP r3, #0 ; if(flag_r3 != 0) 142 VLDMFDNE r1!, {d8 - d15} ; pop FPU register s16~s31 143 ENDIF 144 145 MSR psp, r1 ; update stack pointer 146 147 IF {FPU} != "SoftVFP" 148 ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA. 149 CMP r3, #0 ; if(flag_r3 != 0) 150 BICNE lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA. 151 ENDIF 152 153pendsv_exit 154 ; restore interrupt 155 MSR PRIMASK, r2 156 157 ORR lr, lr, #0x04 158 BX lr 159 ENDP 160 161;/* 162; * void rt_hw_context_switch_to(rt_uint32 to); 163; * r0 --> to 164; * this fucntion is used to perform the first thread switch 165; */ 166rt_hw_context_switch_to PROC 167 EXPORT rt_hw_context_switch_to 168 ; set to thread 169 LDR r1, =rt_interrupt_to_thread 170 STR r0, [r1] 171 172 IF {FPU} != "SoftVFP" 173 ; CLEAR CONTROL.FPCA 174 MRS r2, CONTROL ; read 175 BIC r2, #0x04 ; modify 176 MSR CONTROL, r2 ; write-back 177 ENDIF 178 179 ; set from thread to 0 180 LDR r1, =rt_interrupt_from_thread 181 MOV r0, #0x0 182 STR r0, [r1] 183 184 ; set interrupt flag to 1 185 LDR r1, =rt_thread_switch_interrupt_flag 186 MOV r0, #1 187 STR r0, [r1] 188 189 ; set the PendSV exception priority 190 LDR r0, =NVIC_SYSPRI2 191 LDR r1, =NVIC_PENDSV_PRI 192 LDR.W r2, [r0,#0x00] ; read 193 ORR r1,r1,r2 ; modify 194 STR r1, [r0] ; write-back 195 196 ; trigger the PendSV exception (causes context switch) 197 LDR r0, =NVIC_INT_CTRL 198 LDR r1, =NVIC_PENDSVSET 199 STR r1, [r0] 200 201 ; restore MSP 202 LDR r0, =SCB_VTOR 203 LDR r0, [r0] 204 LDR r0, [r0] 205 MSR msp, r0 206 207 ; enable interrupts at processor level 208 CPSIE F 209 CPSIE I 210 211 ; never reach here! 212 ENDP 213 214; compatible with old version 215rt_hw_interrupt_thread_switch PROC 216 EXPORT rt_hw_interrupt_thread_switch 217 BX lr 218 ENDP 219 220 IMPORT rt_hw_hard_fault_exception 221 EXPORT HardFault_Handler 222 EXPORT MemManage_Handler 223HardFault_Handler PROC 224MemManage_Handler 225 226 ; get current context 227 TST lr, #0x04 ; if(!EXC_RETURN[2]) 228 ITE EQ 229 MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler. 230 MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread. 231 232 STMFD r0!, {r4 - r11} ; push r4 - r11 register 233 IF {FPU} != "SoftVFP" 234 STMFD r0!, {lr} ; push dummy for flag 235 ENDIF 236 STMFD r0!, {lr} ; push exec_return register 237 238 TST lr, #0x04 ; if(!EXC_RETURN[2]) 239 ITE EQ 240 MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP. 241 MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP. 242 243 PUSH {lr} 244 BL rt_hw_hard_fault_exception 245 POP {lr} 246 247 ORR lr, lr, #0x04 248 BX lr 249 ENDP 250 251 ALIGN 4 252 253 END 254