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; * 2009-09-27 Bernard add protect when contex switch occurs 10; * 2012-01-01 aozima support context switch load/store FPU register. 11; * 2013-06-18 aozima add restore MSP feature. 12; * 2013-06-23 aozima support lazy stack optimized. 13; * 2018-07-24 aozima enhancement hard fault exception handler. 14; */ 15 16;/** 17; * @addtogroup cortex-m4 18; */ 19;/*@{*/ 20 21SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register 22NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register 23NVIC_SYSPRI2 EQU 0xE000ED20 ; system priority register (2) 24NVIC_PENDSV_PRI EQU 0x00FF0000 ; PendSV priority value (lowest) 25NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception 26 27 SECTION .text:CODE(2) 28 THUMB 29 REQUIRE8 30 PRESERVE8 31 32 IMPORT rt_thread_switch_interrupt_flag 33 IMPORT rt_interrupt_from_thread 34 IMPORT rt_interrupt_to_thread 35 36;/* 37; * rt_base_t rt_hw_interrupt_disable(); 38; */ 39 EXPORT rt_hw_interrupt_disable 40rt_hw_interrupt_disable: 41 MRS r0, PRIMASK 42 CPSID I 43 BX LR 44 45;/* 46; * void rt_hw_interrupt_enable(rt_base_t level); 47; */ 48 EXPORT rt_hw_interrupt_enable 49rt_hw_interrupt_enable: 50 MSR PRIMASK, r0 51 BX LR 52 53;/* 54; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); 55; * r0 --> from 56; * r1 --> to 57; */ 58 EXPORT rt_hw_context_switch_interrupt 59 EXPORT rt_hw_context_switch 60rt_hw_context_switch_interrupt: 61rt_hw_context_switch: 62 ; set rt_thread_switch_interrupt_flag to 1 63 LDR r2, =rt_thread_switch_interrupt_flag 64 LDR r3, [r2] 65 CMP r3, #1 66 BEQ _reswitch 67 MOV r3, #1 68 STR r3, [r2] 69 70 LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread 71 STR r0, [r2] 72 73_reswitch 74 LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread 75 STR r1, [r2] 76 77 LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch) 78 LDR r1, =NVIC_PENDSVSET 79 STR r1, [r0] 80 BX LR 81 82; r0 --> switch from thread stack 83; r1 --> switch to thread stack 84; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack 85 EXPORT PendSV_Handler 86PendSV_Handler: 87 88 ; disable interrupt to protect context switch 89 MRS r2, PRIMASK 90 CPSID I 91 92 ; get rt_thread_switch_interrupt_flag 93 LDR r0, =rt_thread_switch_interrupt_flag 94 LDR r1, [r0] 95 CBZ r1, pendsv_exit ; pendsv already handled 96 97 ; clear rt_thread_switch_interrupt_flag to 0 98 MOV r1, #0x00 99 STR r1, [r0] 100 101 LDR r0, =rt_interrupt_from_thread 102 LDR r1, [r0] 103 CBZ r1, switch_to_thread ; skip register save at the first time 104 105 MRS r1, psp ; get from thread stack pointer 106 107#if defined ( __ARMVFP__ ) 108 TST lr, #0x10 ; if(!EXC_RETURN[4]) 109 BNE skip_push_fpu 110 VSTMDB r1!, {d8 - d15} ; push FPU register s16~s31 111skip_push_fpu 112#endif 113 114 STMFD r1!, {r4 - r11} ; push r4 - r11 register 115 116#if defined ( __ARMVFP__ ) 117 MOV r4, #0x00 ; flag = 0 118 TST lr, #0x10 ; if(!EXC_RETURN[4]) 119 BNE push_flag 120 MOV r4, #0x01 ; flag = 1 121push_flag 122 ;STMFD r1!, {r4} ; push flag 123 SUB r1, r1, #0x04 124 STR r4, [r1] 125#endif 126 127 LDR r0, [r0] 128 STR r1, [r0] ; update from thread stack pointer 129 130switch_to_thread 131 LDR r1, =rt_interrupt_to_thread 132 LDR r1, [r1] 133 LDR r1, [r1] ; load thread stack pointer 134 135#if defined ( __ARMVFP__ ) 136 LDMFD r1!, {r3} ; pop flag 137#endif 138 139 LDMFD r1!, {r4 - r11} ; pop r4 - r11 register 140 141#if defined ( __ARMVFP__ ) 142 CBZ r3, skip_pop_fpu 143 VLDMIA r1!, {d8 - d15} ; pop FPU register s16~s31 144skip_pop_fpu 145#endif 146 147 MSR psp, r1 ; update stack pointer 148 149#if defined ( __ARMVFP__ ) 150 ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA. 151 CBZ r3, return_without_fpu ; if(flag_r3 != 0) 152 BIC lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA. 153return_without_fpu 154#endif 155 156pendsv_exit 157 ; restore interrupt 158 MSR PRIMASK, r2 159 160 ORR lr, lr, #0x04 161 BX lr 162 163;/* 164; * void rt_hw_context_switch_to(rt_uint32 to); 165; * r0 --> to 166; */ 167 EXPORT rt_hw_context_switch_to 168rt_hw_context_switch_to: 169 LDR r1, =rt_interrupt_to_thread 170 STR r0, [r1] 171 172#if defined ( __ARMVFP__ ) 173 ; CLEAR CONTROL.FPCA 174 MRS r2, CONTROL ; read 175 BIC r2, 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 LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch) 197 LDR r1, =NVIC_PENDSVSET 198 STR r1, [r0] 199 200 ; restore MSP 201 LDR r0, =SCB_VTOR 202 LDR r0, [r0] 203 LDR r0, [r0] 204 NOP 205 MSR msp, r0 206 207 ; enable interrupts at processor level 208 CPSIE F 209 CPSIE I 210 211 ; never reach here! 212 213; compatible with old version 214 EXPORT rt_hw_interrupt_thread_switch 215rt_hw_interrupt_thread_switch: 216 BX lr 217 218 IMPORT rt_hw_hard_fault_exception 219 EXPORT HardFault_Handler 220HardFault_Handler: 221 222 ; get current context 223 MRS r0, msp ; get fault context from handler. 224 TST lr, #0x04 ; if(!EXC_RETURN[2]) 225 BEQ _get_sp_done 226 MRS r0, psp ; get fault context from thread. 227_get_sp_done 228 229 STMFD r0!, {r4 - r11} ; push r4 - r11 register 230 ;STMFD r0!, {lr} ; push exec_return register 231#if defined ( __ARMVFP__ ) 232 SUB r0, r0, #0x04 ; push dummy for flag 233 STR lr, [r0] 234#endif 235 SUB r0, r0, #0x04 236 STR lr, [r0] 237 238 TST lr, #0x04 ; if(!EXC_RETURN[2]) 239 BEQ _update_msp 240 MSR psp, r0 ; update stack pointer to PSP. 241 B _update_done 242_update_msp 243 MSR msp, r0 ; update stack pointer to MSP. 244_update_done 245 246 PUSH {lr} 247 BL rt_hw_hard_fault_exception 248 POP {lr} 249 250 ORR lr, lr, #0x04 251 BX lr 252 253 END 254