[9364cf66] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
[78623bce] | 4 | * @ingroup ScoreCPU |
---|
[39c8fdb] | 5 | * |
---|
[9364cf66] | 6 | * @brief ARM interrupt exception prologue and epilogue. |
---|
| 7 | */ |
---|
| 8 | |
---|
| 9 | /* |
---|
[e7d3967] | 10 | * Copyright (c) 2009-2014 embedded brains GmbH. All rights reserved. |
---|
[cfd8d7a] | 11 | * |
---|
| 12 | * embedded brains GmbH |
---|
| 13 | * Dornierstr. 4 |
---|
| 14 | * 82178 Puchheim |
---|
| 15 | * Germany |
---|
| 16 | * <rtems@embedded-brains.de> |
---|
[9364cf66] | 17 | * |
---|
| 18 | * The license and distribution terms for this file may be |
---|
| 19 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 20 | * http://www.rtems.org/license/LICENSE. |
---|
[9364cf66] | 21 | */ |
---|
| 22 | |
---|
| 23 | /* |
---|
[9db18dd] | 24 | * The upper EXCHANGE_SIZE bytes of the INT stack area are used for data |
---|
| 25 | * exchange between INT and SVC mode. Below of this is the actual INT stack. |
---|
| 26 | * The exchange area is only accessed if INT is disabled. |
---|
[9364cf66] | 27 | */ |
---|
| 28 | |
---|
[0acc9af3] | 29 | #ifdef HAVE_CONFIG_H |
---|
| 30 | #include "config.h" |
---|
| 31 | #endif |
---|
| 32 | |
---|
[39c8fdb] | 33 | #include <rtems/asm.h> |
---|
| 34 | |
---|
[c5ed148] | 35 | #ifdef ARM_MULTILIB_ARCH_V4 |
---|
| 36 | |
---|
[9db18dd] | 37 | #define EXCHANGE_LR r4 |
---|
| 38 | #define EXCHANGE_SPSR r5 |
---|
| 39 | #define EXCHANGE_CPSR r6 |
---|
[0756790] | 40 | #define EXCHANGE_INT_SP r8 |
---|
[9364cf66] | 41 | |
---|
[9db18dd] | 42 | #define EXCHANGE_LIST {EXCHANGE_LR, EXCHANGE_SPSR, EXCHANGE_CPSR, EXCHANGE_INT_SP} |
---|
| 43 | #define EXCHANGE_SIZE 16 |
---|
[9364cf66] | 44 | |
---|
[0756790] | 45 | #define SELF_CPU_CONTROL r7 |
---|
[e7d3967] | 46 | #define SP_OF_INTERRUPTED_CONTEXT r9 |
---|
[0756790] | 47 | |
---|
| 48 | #define CONTEXT_LIST {r0, r1, r2, r3, EXCHANGE_LR, EXCHANGE_SPSR, SELF_CPU_CONTROL, r12} |
---|
| 49 | #define CONTEXT_SIZE 32 |
---|
[9364cf66] | 50 | |
---|
[9db18dd] | 51 | .arm |
---|
[370c2c80] | 52 | .globl _ARMV4_Exception_interrupt |
---|
| 53 | _ARMV4_Exception_interrupt: |
---|
[9364cf66] | 54 | |
---|
[9db18dd] | 55 | /* Save exchange registers to exchange area */ |
---|
| 56 | stmdb sp, EXCHANGE_LIST |
---|
[9364cf66] | 57 | |
---|
[9db18dd] | 58 | /* Set exchange registers */ |
---|
| 59 | mov EXCHANGE_LR, lr |
---|
[18e1e5b] | 60 | mrs EXCHANGE_SPSR, SPSR |
---|
| 61 | mrs EXCHANGE_CPSR, CPSR |
---|
[9db18dd] | 62 | sub EXCHANGE_INT_SP, sp, #EXCHANGE_SIZE |
---|
[9364cf66] | 63 | |
---|
| 64 | /* Switch to SVC mode */ |
---|
[9db18dd] | 65 | orr EXCHANGE_CPSR, EXCHANGE_CPSR, #0x1 |
---|
[18e1e5b] | 66 | msr CPSR_c, EXCHANGE_CPSR |
---|
[9364cf66] | 67 | |
---|
[9db18dd] | 68 | /* |
---|
[e7d3967] | 69 | * Save context. We save the link register separately because it has |
---|
| 70 | * to be restored in SVC mode. The other registers can be restored in |
---|
| 71 | * INT mode. Ensure that stack remains 8 byte aligned. Use register |
---|
| 72 | * necessary for the stack alignment for the stack pointer of the |
---|
| 73 | * interrupted context. |
---|
[9db18dd] | 74 | */ |
---|
| 75 | stmdb sp!, CONTEXT_LIST |
---|
[e7d3967] | 76 | stmdb sp!, {SP_OF_INTERRUPTED_CONTEXT, lr} |
---|
[9364cf66] | 77 | |
---|
[cfd8d7a] | 78 | #ifdef ARM_MULTILIB_VFP_D32 |
---|
| 79 | /* Save VFP context */ |
---|
| 80 | vmrs r0, FPSCR |
---|
[e7d3967] | 81 | vstmdb sp!, {d0-d7} |
---|
| 82 | vstmdb sp!, {d16-d31} |
---|
| 83 | stmdb sp!, {r0, r1} |
---|
[cfd8d7a] | 84 | #endif |
---|
| 85 | |
---|
[0756790] | 86 | /* Get per-CPU control of current processor */ |
---|
| 87 | GET_SELF_CPU_CONTROL SELF_CPU_CONTROL, r1 |
---|
[f2f211c5] | 88 | |
---|
[9db18dd] | 89 | /* Remember INT stack pointer */ |
---|
| 90 | mov r1, EXCHANGE_INT_SP |
---|
[9364cf66] | 91 | |
---|
[9db18dd] | 92 | /* Restore exchange registers from exchange area */ |
---|
| 93 | ldmia r1, EXCHANGE_LIST |
---|
[9364cf66] | 94 | |
---|
[9db18dd] | 95 | /* Get interrupt nest level */ |
---|
[0756790] | 96 | ldr r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL] |
---|
[9364cf66] | 97 | |
---|
[9db18dd] | 98 | /* Switch stack if necessary and save original stack pointer */ |
---|
[e7d3967] | 99 | mov SP_OF_INTERRUPTED_CONTEXT, sp |
---|
[9db18dd] | 100 | cmp r2, #0 |
---|
| 101 | moveq sp, r1 |
---|
[9364cf66] | 102 | |
---|
| 103 | /* Switch to THUMB instructions if necessary */ |
---|
[e7d3967] | 104 | SWITCH_FROM_ARM_TO_THUMB r1 |
---|
[9364cf66] | 105 | |
---|
[9db18dd] | 106 | /* Increment interrupt nest and thread dispatch disable level */ |
---|
[0756790] | 107 | ldr r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL] |
---|
[9db18dd] | 108 | add r2, #1 |
---|
| 109 | add r3, #1 |
---|
[0756790] | 110 | str r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL] |
---|
| 111 | str r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL] |
---|
[9364cf66] | 112 | |
---|
[148d6e9] | 113 | #ifdef RTEMS_PROFILING |
---|
| 114 | cmp r2, #1 |
---|
| 115 | bne profiling_entry_done |
---|
| 116 | bl _CPU_Counter_read |
---|
| 117 | push {r0, r1} |
---|
| 118 | profiling_entry_done: |
---|
| 119 | #endif |
---|
| 120 | |
---|
[9db18dd] | 121 | /* Call BSP dependent interrupt dispatcher */ |
---|
[9364cf66] | 122 | bl bsp_interrupt_dispatch |
---|
| 123 | |
---|
| 124 | /* Decrement interrupt nest and thread dispatch disable level */ |
---|
[0756790] | 125 | ldr r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL] |
---|
| 126 | ldr r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL] |
---|
[9db18dd] | 127 | sub r2, #1 |
---|
| 128 | sub r3, #1 |
---|
[0756790] | 129 | str r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL] |
---|
| 130 | str r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL] |
---|
[9364cf66] | 131 | |
---|
[148d6e9] | 132 | #ifdef RTEMS_PROFILING |
---|
| 133 | cmp r2, #0 |
---|
| 134 | bne profiling_exit_done |
---|
| 135 | bl _CPU_Counter_read |
---|
| 136 | pop {r1, r3} |
---|
| 137 | mov r2, r0 |
---|
| 138 | mov r0, SELF_CPU_CONTROL |
---|
| 139 | bl _Profiling_Outer_most_interrupt_entry_and_exit |
---|
| 140 | ldr r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL] |
---|
| 141 | profiling_exit_done: |
---|
| 142 | #endif |
---|
| 143 | |
---|
[9db18dd] | 144 | /* Restore stack pointer */ |
---|
[e7d3967] | 145 | mov sp, SP_OF_INTERRUPTED_CONTEXT |
---|
[9364cf66] | 146 | |
---|
[9db18dd] | 147 | /* Check thread dispatch disable level */ |
---|
[9364cf66] | 148 | cmp r3, #0 |
---|
| 149 | bne thread_dispatch_done |
---|
| 150 | |
---|
[9db18dd] | 151 | /* Check context switch necessary */ |
---|
[0756790] | 152 | ldrb r1, [SELF_CPU_CONTROL, #PER_CPU_DISPATCH_NEEDED] |
---|
[9db18dd] | 153 | cmp r1, #0 |
---|
| 154 | beq thread_dispatch_done |
---|
[9364cf66] | 155 | |
---|
[9db18dd] | 156 | /* This aligns thread_dispatch_done on a 4 byte boundary */ |
---|
| 157 | #ifdef __thumb__ |
---|
| 158 | nop |
---|
| 159 | #endif /* __thumb__ */ |
---|
[9364cf66] | 160 | |
---|
[9db18dd] | 161 | /* Thread dispatch */ |
---|
| 162 | bl _Thread_Dispatch |
---|
[9364cf66] | 163 | |
---|
[9db18dd] | 164 | thread_dispatch_done: |
---|
[9364cf66] | 165 | |
---|
[9db18dd] | 166 | /* Switch to ARM instructions if necessary */ |
---|
| 167 | SWITCH_FROM_THUMB_TO_ARM |
---|
[9364cf66] | 168 | |
---|
[cfd8d7a] | 169 | #ifdef ARM_MULTILIB_VFP_D32 |
---|
| 170 | /* Restore VFP context */ |
---|
[e7d3967] | 171 | ldmia sp!, {r0, r1} |
---|
| 172 | vldmia sp!, {d16-d31} |
---|
| 173 | vldmia sp!, {d0-d7} |
---|
[cfd8d7a] | 174 | vmsr FPSCR, r0 |
---|
| 175 | #endif |
---|
| 176 | |
---|
[e7d3967] | 177 | /* Restore SP_OF_INTERRUPTED_CONTEXT register and link register */ |
---|
| 178 | ldmia sp!, {SP_OF_INTERRUPTED_CONTEXT, lr} |
---|
[9364cf66] | 179 | |
---|
[9db18dd] | 180 | /* |
---|
| 181 | * XXX: Remember and restore stack pointer. The data on the stack is |
---|
| 182 | * still in use. So the stack is now in an inconsistent state. The |
---|
| 183 | * FIQ handler implementation must not use this area. |
---|
| 184 | */ |
---|
| 185 | mov r0, sp |
---|
| 186 | add sp, #CONTEXT_SIZE |
---|
[9364cf66] | 187 | |
---|
[9db18dd] | 188 | /* Get INT mode program status register */ |
---|
[18e1e5b] | 189 | mrs r1, CPSR |
---|
[9db18dd] | 190 | bic r1, r1, #0x1 |
---|
[9364cf66] | 191 | |
---|
[9db18dd] | 192 | /* Switch to INT mode */ |
---|
[18e1e5b] | 193 | msr CPSR_c, r1 |
---|
[9364cf66] | 194 | |
---|
[9db18dd] | 195 | /* Save EXCHANGE_LR and EXCHANGE_SPSR registers to exchange area */ |
---|
| 196 | stmdb sp!, {EXCHANGE_LR, EXCHANGE_SPSR} |
---|
[9364cf66] | 197 | |
---|
[9db18dd] | 198 | /* Restore context */ |
---|
| 199 | ldmia r0, CONTEXT_LIST |
---|
[9364cf66] | 200 | |
---|
[9db18dd] | 201 | /* Set return address and program status */ |
---|
| 202 | mov lr, EXCHANGE_LR |
---|
[18e1e5b] | 203 | msr SPSR_fsxc, EXCHANGE_SPSR |
---|
[9364cf66] | 204 | |
---|
[9db18dd] | 205 | /* Restore EXCHANGE_LR and EXCHANGE_SPSR registers from exchange area */ |
---|
| 206 | ldmia sp!, {EXCHANGE_LR, EXCHANGE_SPSR} |
---|
[9364cf66] | 207 | |
---|
| 208 | /* Return from interrupt */ |
---|
| 209 | subs pc, lr, #4 |
---|
[c5ed148] | 210 | |
---|
| 211 | #endif /* ARM_MULTILIB_ARCH_V4 */ |
---|