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