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