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-10-11 Bernard First version 9*10465441SEvalZero * 2010-12-29 onelife Modify for EFM32 10*10465441SEvalZero * 2011-06-17 onelife Merge all of the assembly source code into context_gcc.S 11*10465441SEvalZero * 2011-07-12 onelife Add interrupt context check function 12*10465441SEvalZero * 2013-06-18 aozima add restore MSP feature. 13*10465441SEvalZero * 2013-07-09 aozima enhancement hard fault exception handler. 14*10465441SEvalZero */ 15*10465441SEvalZero 16*10465441SEvalZero .cpu cortex-m3 17*10465441SEvalZero .fpu softvfp 18*10465441SEvalZero .syntax unified 19*10465441SEvalZero .thumb 20*10465441SEvalZero .text 21*10465441SEvalZero 22*10465441SEvalZero .equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */ 23*10465441SEvalZero .equ ICSR, 0xE000ED04 /* interrupt control state register */ 24*10465441SEvalZero .equ PENDSVSET_BIT, 0x10000000 /* value to trigger PendSV exception */ 25*10465441SEvalZero 26*10465441SEvalZero .equ SHPR3, 0xE000ED20 /* system priority register (3) */ 27*10465441SEvalZero .equ PENDSV_PRI_LOWEST, 0x00FF0000 /* PendSV priority value (lowest) */ 28*10465441SEvalZero 29*10465441SEvalZero/* 30*10465441SEvalZero * rt_base_t rt_hw_interrupt_disable(); 31*10465441SEvalZero */ 32*10465441SEvalZero .global rt_hw_interrupt_disable 33*10465441SEvalZero .type rt_hw_interrupt_disable, %function 34*10465441SEvalZerort_hw_interrupt_disable: 35*10465441SEvalZero MRS R0, PRIMASK 36*10465441SEvalZero CPSID I 37*10465441SEvalZero BX LR 38*10465441SEvalZero 39*10465441SEvalZero/* 40*10465441SEvalZero * void rt_hw_interrupt_enable(rt_base_t level); 41*10465441SEvalZero */ 42*10465441SEvalZero .global rt_hw_interrupt_enable 43*10465441SEvalZero .type rt_hw_interrupt_enable, %function 44*10465441SEvalZerort_hw_interrupt_enable: 45*10465441SEvalZero MSR PRIMASK, R0 46*10465441SEvalZero BX LR 47*10465441SEvalZero 48*10465441SEvalZero/* 49*10465441SEvalZero * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); 50*10465441SEvalZero * R0 --> from 51*10465441SEvalZero * R1 --> to 52*10465441SEvalZero */ 53*10465441SEvalZero .global rt_hw_context_switch_interrupt 54*10465441SEvalZero .type rt_hw_context_switch_interrupt, %function 55*10465441SEvalZero .global rt_hw_context_switch 56*10465441SEvalZero .type rt_hw_context_switch, %function 57*10465441SEvalZerort_hw_context_switch_interrupt: 58*10465441SEvalZerort_hw_context_switch: 59*10465441SEvalZero /* set rt_thread_switch_interrupt_flag to 1 */ 60*10465441SEvalZero LDR R2, =rt_thread_switch_interrupt_flag 61*10465441SEvalZero LDR R3, [R2] 62*10465441SEvalZero CMP R3, #1 63*10465441SEvalZero BEQ _reswitch 64*10465441SEvalZero MOV R3, #1 65*10465441SEvalZero STR R3, [R2] 66*10465441SEvalZero 67*10465441SEvalZero LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */ 68*10465441SEvalZero STR R0, [R2] 69*10465441SEvalZero 70*10465441SEvalZero_reswitch: 71*10465441SEvalZero LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */ 72*10465441SEvalZero STR R1, [R2] 73*10465441SEvalZero 74*10465441SEvalZero LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */ 75*10465441SEvalZero LDR R1, =PENDSVSET_BIT 76*10465441SEvalZero STR R1, [R0] 77*10465441SEvalZero BX LR 78*10465441SEvalZero 79*10465441SEvalZero/* R0 --> switch from thread stack 80*10465441SEvalZero * R1 --> switch to thread stack 81*10465441SEvalZero * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack 82*10465441SEvalZero */ 83*10465441SEvalZero .global PendSV_Handler 84*10465441SEvalZero .type PendSV_Handler, %function 85*10465441SEvalZeroPendSV_Handler: 86*10465441SEvalZero /* disable interrupt to protect context switch */ 87*10465441SEvalZero MRS R2, PRIMASK 88*10465441SEvalZero CPSID I 89*10465441SEvalZero 90*10465441SEvalZero /* get rt_thread_switch_interrupt_flag */ 91*10465441SEvalZero LDR R0, =rt_thread_switch_interrupt_flag 92*10465441SEvalZero LDR R1, [R0] 93*10465441SEvalZero CBZ R1, pendsv_exit /* pendsv aLReady handled */ 94*10465441SEvalZero 95*10465441SEvalZero /* clear rt_thread_switch_interrupt_flag to 0 */ 96*10465441SEvalZero MOV R1, #0 97*10465441SEvalZero STR R1, [R0] 98*10465441SEvalZero 99*10465441SEvalZero LDR R0, =rt_interrupt_from_thread 100*10465441SEvalZero LDR R1, [R0] 101*10465441SEvalZero CBZ R1, switch_to_thread /* skip register save at the first time */ 102*10465441SEvalZero 103*10465441SEvalZero MRS R1, PSP /* get from thread stack pointer */ 104*10465441SEvalZero STMFD R1!, {R4 - R11} /* push R4 - R11 register */ 105*10465441SEvalZero LDR R0, [R0] 106*10465441SEvalZero STR R1, [R0] /* update from thread stack pointer */ 107*10465441SEvalZero 108*10465441SEvalZeroswitch_to_thread: 109*10465441SEvalZero LDR R1, =rt_interrupt_to_thread 110*10465441SEvalZero LDR R1, [R1] 111*10465441SEvalZero LDR R1, [R1] /* load thread stack pointer */ 112*10465441SEvalZero 113*10465441SEvalZero LDMFD R1!, {R4 - R11} /* pop R4 - R11 register */ 114*10465441SEvalZero MSR PSP, R1 /* update stack pointer */ 115*10465441SEvalZero 116*10465441SEvalZeropendsv_exit: 117*10465441SEvalZero /* restore interrupt */ 118*10465441SEvalZero MSR PRIMASK, R2 119*10465441SEvalZero 120*10465441SEvalZero ORR LR, LR, #0x04 121*10465441SEvalZero BX LR 122*10465441SEvalZero 123*10465441SEvalZero/* 124*10465441SEvalZero * void rt_hw_context_switch_to(rt_uint32 to); 125*10465441SEvalZero * R0 --> to 126*10465441SEvalZero */ 127*10465441SEvalZero .global rt_hw_context_switch_to 128*10465441SEvalZero .type rt_hw_context_switch_to, %function 129*10465441SEvalZerort_hw_context_switch_to: 130*10465441SEvalZero LDR R1, =rt_interrupt_to_thread 131*10465441SEvalZero STR R0, [R1] 132*10465441SEvalZero 133*10465441SEvalZero /* set from thread to 0 */ 134*10465441SEvalZero LDR R1, =rt_interrupt_from_thread 135*10465441SEvalZero MOV R0, #0 136*10465441SEvalZero STR R0, [R1] 137*10465441SEvalZero 138*10465441SEvalZero /* set interrupt flag to 1 */ 139*10465441SEvalZero LDR R1, =rt_thread_switch_interrupt_flag 140*10465441SEvalZero MOV R0, #1 141*10465441SEvalZero STR R0, [R1] 142*10465441SEvalZero 143*10465441SEvalZero /* set the PendSV exception priority */ 144*10465441SEvalZero LDR R0, =SHPR3 145*10465441SEvalZero LDR R1, =PENDSV_PRI_LOWEST 146*10465441SEvalZero LDR.W R2, [R0,#0] /* read */ 147*10465441SEvalZero ORR R1, R1, R2 /* modify */ 148*10465441SEvalZero STR R1, [R0] /* write-back */ 149*10465441SEvalZero 150*10465441SEvalZero LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */ 151*10465441SEvalZero LDR R1, =PENDSVSET_BIT 152*10465441SEvalZero STR R1, [R0] 153*10465441SEvalZero 154*10465441SEvalZero /* restore MSP */ 155*10465441SEvalZero LDR r0, =SCB_VTOR 156*10465441SEvalZero LDR r0, [r0] 157*10465441SEvalZero LDR r0, [r0] 158*10465441SEvalZero NOP 159*10465441SEvalZero MSR msp, r0 160*10465441SEvalZero 161*10465441SEvalZero /* enable interrupts at processor level */ 162*10465441SEvalZero CPSIE F 163*10465441SEvalZero CPSIE I 164*10465441SEvalZero 165*10465441SEvalZero /* never reach here! */ 166*10465441SEvalZero 167*10465441SEvalZero/* compatible with old version */ 168*10465441SEvalZero .global rt_hw_interrupt_thread_switch 169*10465441SEvalZero .type rt_hw_interrupt_thread_switch, %function 170*10465441SEvalZerort_hw_interrupt_thread_switch: 171*10465441SEvalZero BX LR 172*10465441SEvalZero NOP 173*10465441SEvalZero 174*10465441SEvalZero .global HardFault_Handler 175*10465441SEvalZero .type HardFault_Handler, %function 176*10465441SEvalZeroHardFault_Handler: 177*10465441SEvalZero /* get current context */ 178*10465441SEvalZero MRS r0, msp /* get fault context from handler. */ 179*10465441SEvalZero TST lr, #0x04 /* if(!EXC_RETURN[2]) */ 180*10465441SEvalZero BEQ _get_sp_done 181*10465441SEvalZero MRS r0, psp /* get fault context from thread. */ 182*10465441SEvalZero_get_sp_done: 183*10465441SEvalZero 184*10465441SEvalZero STMFD r0!, {r4 - r11} /* push r4 - r11 register */ 185*10465441SEvalZero STMFD r0!, {lr} /* push exec_return register */ 186*10465441SEvalZero 187*10465441SEvalZero TST lr, #0x04 /* if(!EXC_RETURN[2]) */ 188*10465441SEvalZero BEQ _update_msp 189*10465441SEvalZero MSR psp, r0 /* update stack pointer to PSP. */ 190*10465441SEvalZero B _update_done 191*10465441SEvalZero_update_msp: 192*10465441SEvalZero MSR msp, r0 /* update stack pointer to MSP. */ 193*10465441SEvalZero_update_done: 194*10465441SEvalZero 195*10465441SEvalZero PUSH {LR} 196*10465441SEvalZero BL rt_hw_hard_fault_exception 197*10465441SEvalZero POP {LR} 198*10465441SEvalZero 199*10465441SEvalZero ORR LR, LR, #0x04 200*10465441SEvalZero BX LR 201*10465441SEvalZero 202*10465441SEvalZero/* 203*10465441SEvalZero * rt_uint32_t rt_hw_interrupt_check(void); 204*10465441SEvalZero * R0 --> state 205*10465441SEvalZero */ 206*10465441SEvalZero .global rt_hw_interrupt_check 207*10465441SEvalZero .type rt_hw_interrupt_check, %function 208*10465441SEvalZerort_hw_interrupt_check: 209*10465441SEvalZero MRS R0, IPSR 210*10465441SEvalZero BX LR 211