source: rtems/cpukit/score/cpu/arm/arm_exc_interrupt.S @ fbda4a8

4.115
Last change on this file since fbda4a8 was fbda4a8, checked in by Sebastian Huber <sebastian.huber@…>, on 07/01/14 at 08:48:28

score: PR2183: Fix context switch on SMP

Fix context switch on SMP for ARM, PowerPC and SPARC.

Atomically test and set the is executing indicator of the heir context
to ensure that at most one processor uses the heir context. Break the
busy wait loop also due to heir updates.

  • Property mode set to 100644
File size: 5.2 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreCPU
5 *
6 * @brief ARM interrupt exception prologue and epilogue.
7 */
8
9/*
10 * Copyright (c) 2009-2014 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23/*
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.
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <rtems/asm.h>
34
35#ifdef ARM_MULTILIB_ARCH_V4
36
37#define EXCHANGE_LR r4
38#define EXCHANGE_SPSR r5
39#define EXCHANGE_CPSR r6
40#define EXCHANGE_INT_SP r8
41
42#define EXCHANGE_LIST {EXCHANGE_LR, EXCHANGE_SPSR, EXCHANGE_CPSR, EXCHANGE_INT_SP}
43#define EXCHANGE_SIZE 16
44
45#define SELF_CPU_CONTROL r7
46#define SP_OF_INTERRUPTED_CONTEXT r9
47
48#define CONTEXT_LIST {r0, r1, r2, r3, EXCHANGE_LR, EXCHANGE_SPSR, SELF_CPU_CONTROL, r12}
49#define CONTEXT_SIZE 32
50
51.arm
52.globl _ARMV4_Exception_interrupt
53_ARMV4_Exception_interrupt:
54
55        /* Save exchange registers to exchange area */
56        stmdb   sp, EXCHANGE_LIST
57
58        /* Set exchange registers */
59        mov     EXCHANGE_LR, lr
60        mrs     EXCHANGE_SPSR, SPSR
61        mrs     EXCHANGE_CPSR, CPSR
62        sub     EXCHANGE_INT_SP, sp, #EXCHANGE_SIZE
63
64        /* Switch to SVC mode */
65        orr     EXCHANGE_CPSR, EXCHANGE_CPSR, #0x1
66        msr     CPSR_c, EXCHANGE_CPSR
67
68        /*
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.
74         */
75        stmdb   sp!, CONTEXT_LIST
76        stmdb   sp!, {SP_OF_INTERRUPTED_CONTEXT, lr}
77
78#ifdef ARM_MULTILIB_VFP_D32
79        /* Save VFP context */
80        vmrs    r0, FPSCR
81        vstmdb  sp!, {d0-d7}
82        vstmdb  sp!, {d16-d31}
83        stmdb   sp!, {r0, r1}
84#endif
85
86        /* Get per-CPU control of current processor */
87        GET_SELF_CPU_CONTROL    SELF_CPU_CONTROL, r1
88
89        /* Remember INT stack pointer */
90        mov     r1, EXCHANGE_INT_SP
91
92        /* Restore exchange registers from exchange area */
93        ldmia   r1, EXCHANGE_LIST
94
95        /* Get interrupt nest level */
96        ldr     r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL]
97
98        /* Switch stack if necessary and save original stack pointer */
99        mov     SP_OF_INTERRUPTED_CONTEXT, sp
100        cmp     r2, #0
101        moveq   sp, r1
102
103        /* Switch to THUMB instructions if necessary */
104        SWITCH_FROM_ARM_TO_THUMB        r1
105
106        /* Increment interrupt nest and thread dispatch disable level */
107        ldr     r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
108        add     r2, #1
109        add     r3, #1
110        str     r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL]
111        str     r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
112
113#ifdef RTEMS_PROFILING
114        cmp     r2, #1
115        bne     profiling_entry_done
116        bl      _CPU_Counter_read
117        push    {r0, r1}
118profiling_entry_done:
119#endif
120
121        /* Call BSP dependent interrupt dispatcher */
122        bl      bsp_interrupt_dispatch
123
124        /* Decrement interrupt nest and thread dispatch disable level */
125        ldr     r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL]
126        ldr     r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
127        sub     r2, #1
128        sub     r3, #1
129        str     r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL]
130        str     r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
131
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]
141profiling_exit_done:
142#endif
143
144        /* Restore stack pointer */
145        mov     sp, SP_OF_INTERRUPTED_CONTEXT
146
147        /* Check thread dispatch disable level */
148        cmp     r3, #0
149        bne     thread_dispatch_done
150
151        /* Check context switch necessary */
152        ldrb    r1, [SELF_CPU_CONTROL, #PER_CPU_DISPATCH_NEEDED]
153        cmp     r1, #0
154        beq     thread_dispatch_done
155
156        /* This aligns thread_dispatch_done on a 4 byte boundary */
157#ifdef __thumb__
158        nop
159#endif /* __thumb__ */
160
161        /* Thread dispatch */
162        bl      _Thread_Dispatch
163
164thread_dispatch_done:
165
166        /* Switch to ARM instructions if necessary */
167        SWITCH_FROM_THUMB_TO_ARM
168
169#ifdef ARM_MULTILIB_VFP_D32
170        /* Restore VFP context */
171        ldmia   sp!, {r0, r1}
172        vldmia  sp!, {d16-d31}
173        vldmia  sp!, {d0-d7}
174        vmsr    FPSCR, r0
175#endif
176
177        /* Restore SP_OF_INTERRUPTED_CONTEXT register and link register */
178        ldmia   sp!, {SP_OF_INTERRUPTED_CONTEXT, lr}
179
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
187
188        /* Get INT mode program status register */
189        mrs     r1, CPSR
190        bic     r1, r1, #0x1
191
192        /* Switch to INT mode */
193        msr     CPSR_c, r1
194
195        /* Save EXCHANGE_LR and EXCHANGE_SPSR registers to exchange area */
196        stmdb   sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
197
198        /* Restore context */
199        ldmia   r0, CONTEXT_LIST
200
201        /* Set return address and program status */
202        mov     lr, EXCHANGE_LR
203        msr     SPSR_fsxc, EXCHANGE_SPSR
204
205        /* Restore EXCHANGE_LR and EXCHANGE_SPSR registers from exchange area */
206        ldmia   sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
207
208        /* Return from interrupt */
209        subs    pc, lr, #4
210
211#endif /* ARM_MULTILIB_ARCH_V4 */
Note: See TracBrowser for help on using the repository browser.