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 * 2010-01-25 Bernard first version 9 * 2012-06-01 aozima set pendsv priority to 0xFF. 10 * 2012-08-17 aozima fixed bug: store r8 - r11. 11 * 2013-02-20 aozima port to gcc. 12 * 2013-06-18 aozima add restore MSP feature. 13 * 2013-11-04 bright fixed hardfault bug for gcc. 14 */ 15 16 .cpu cortex-m0 17 .fpu softvfp 18 .syntax unified 19 .thumb 20 .text 21 22 .equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */ 23 .equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */ 24 .equ NVIC_SHPR3, 0xE000ED20 /* system priority register (3) */ 25 .equ NVIC_PENDSV_PRI, 0x00FF0000 /* PendSV priority value (lowest) */ 26 .equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */ 27 28/* 29 * rt_base_t rt_hw_interrupt_disable(); 30 */ 31 .global rt_hw_interrupt_disable 32 .type rt_hw_interrupt_disable, %function 33rt_hw_interrupt_disable: 34 MRS R0, PRIMASK 35 CPSID I 36 BX LR 37 38/* 39 * void rt_hw_interrupt_enable(rt_base_t level); 40 */ 41 .global rt_hw_interrupt_enable 42 .type rt_hw_interrupt_enable, %function 43rt_hw_interrupt_enable: 44 MSR PRIMASK, R0 45 BX LR 46 47/* 48 * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); 49 * R0 --> from 50 * R1 --> to 51 */ 52 .global rt_hw_context_switch_interrupt 53 .type rt_hw_context_switch_interrupt, %function 54 .global rt_hw_context_switch 55 .type rt_hw_context_switch, %function 56rt_hw_context_switch_interrupt: 57rt_hw_context_switch: 58 /* set rt_thread_switch_interrupt_flag to 1 */ 59 LDR R2, =rt_thread_switch_interrupt_flag 60 LDR R3, [R2] 61 CMP R3, #1 62 BEQ _reswitch 63 MOVS R3, #1 64 STR R3, [R2] 65 66 LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */ 67 STR R0, [R2] 68 69_reswitch: 70 LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */ 71 STR R1, [R2] 72 73 LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */ 74 LDR R1, =NVIC_PENDSVSET 75 STR R1, [R0] 76 BX LR 77 78/* R0 --> switch from thread stack 79 * R1 --> switch to thread stack 80 * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack 81 */ 82 .global PendSV_Handler 83 .type PendSV_Handler, %function 84PendSV_Handler: 85 /* disable interrupt to protect context switch */ 86 MRS R2, PRIMASK 87 CPSID I 88 89 /* get rt_thread_switch_interrupt_flag */ 90 LDR R0, =rt_thread_switch_interrupt_flag 91 LDR R1, [R0] 92 CMP R1, #0x00 93 BEQ pendsv_exit /* pendsv aLReady handled */ 94 95 /* clear rt_thread_switch_interrupt_flag to 0 */ 96 MOVS R1, #0 97 STR R1, [R0] 98 99 LDR R0, =rt_interrupt_from_thread 100 LDR R1, [R0] 101 CMP R1, #0x00 102 BEQ switch_to_thread /* skip register save at the first time */ 103 104 MRS R1, PSP /* get from thread stack pointer */ 105 106 SUBS R1, R1, #0x20 /* space for {R4 - R7} and {R8 - R11} */ 107 LDR R0, [R0] 108 STR R1, [R0] /* update from thread stack pointer */ 109 110 STMIA R1!, {R4 - R7} /* push thread {R4 - R7} register to thread stack */ 111 112 MOV R4, R8 /* mov thread {R8 - R11} to {R4 - R7} */ 113 MOV R5, R9 114 MOV R6, R10 115 MOV R7, R11 116 STMIA R1!, {R4 - R7} /* push thread {R8 - R11} high register to thread stack */ 117switch_to_thread: 118 LDR R1, =rt_interrupt_to_thread 119 LDR R1, [R1] 120 LDR R1, [R1] /* load thread stack pointer */ 121 122 LDMIA R1!, {R4 - R7} /* pop thread {R4 - R7} register from thread stack */ 123 PUSH {R4 - R7} /* push {R4 - R7} to MSP for copy {R8 - R11} */ 124 125 LDMIA R1!, {R4 - R7} /* pop thread {R8 - R11} high register from thread stack to {R4 - R7} */ 126 MOV R8, R4 /* mov {R4 - R7} to {R8 - R11} */ 127 MOV R9, R5 128 MOV R10, R6 129 MOV R11, R7 130 131 POP {R4 - R7} /* pop {R4 - R7} from MSP */ 132 133 MSR PSP, R1 /* update stack pointer */ 134 135pendsv_exit: 136 /* restore interrupt */ 137 MSR PRIMASK, R2 138 139 MOVS R0, #0x04 140 RSBS R0, R0, #0x00 141 BX R0 142/* 143 * void rt_hw_context_switch_to(rt_uint32 to); 144 * R0 --> to 145 */ 146 .global rt_hw_context_switch_to 147 .type rt_hw_context_switch_to, %function 148rt_hw_context_switch_to: 149 LDR R1, =rt_interrupt_to_thread 150 STR R0, [R1] 151 152 /* set from thread to 0 */ 153 LDR R1, =rt_interrupt_from_thread 154 MOVS R0, #0 155 STR R0, [R1] 156 157 /* set interrupt flag to 1 */ 158 LDR R1, =rt_thread_switch_interrupt_flag 159 MOVS R0, #1 160 STR R0, [R1] 161 162 /* set the PendSV exception priority */ 163 LDR R0, =NVIC_SHPR3 164 LDR R1, =NVIC_PENDSV_PRI 165 LDR R2, [R0,#0x00] /* read */ 166 ORRS R1, R1, R2 /* modify */ 167 STR R1, [R0] /* write-back */ 168 169 LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */ 170 LDR R1, =NVIC_PENDSVSET 171 STR R1, [R0] 172 NOP 173 /* restore MSP */ 174 LDR R0, =SCB_VTOR 175 LDR R0, [R0] 176 LDR R0, [R0] 177 NOP 178 MSR MSP, R0 179 180 /* enable interrupts at processor level */ 181 CPSIE I 182 183 /* never reach here! */ 184 185/* compatible with old version */ 186 .global rt_hw_interrupt_thread_switch 187 .type rt_hw_interrupt_thread_switch, %function 188rt_hw_interrupt_thread_switch: 189 BX LR 190 NOP 191 192 .global HardFault_Handler 193 .type HardFault_Handler, %function 194HardFault_Handler: 195 /* get current context */ 196 MRS R0, PSP /* get fault thread stack pointer */ 197 PUSH {LR} 198 BL rt_hw_hard_fault_exception 199 POP {PC} 200 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