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

4.115
Last change on this file since d9bd5cd6 was 18e1e5b, checked in by Sebastian Huber <sebastian.huber@…>, on 05/23/13 at 07:04:19

arm: Fix CPSR and SPSR access

The GNU assembler translates for example a

msr spsr, rN

into

msr SPSR_fc, rN

This would update only a subset of the register and leads to an
incomplete exceptions restore sequence resulting in system corruption.
Correct is this:

msr SPSR_fsxc, rN

  • Property mode set to 100644
File size: 4.5 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-2013 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.com/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#include <rtems/score/percpu.h>
35
36#ifdef ARM_MULTILIB_ARCH_V4
37
38#define EXCHANGE_LR r4
39#define EXCHANGE_SPSR r5
40#define EXCHANGE_CPSR r6
41#define EXCHANGE_INT_SP r7
42
43#define EXCHANGE_LIST {EXCHANGE_LR, EXCHANGE_SPSR, EXCHANGE_CPSR, EXCHANGE_INT_SP}
44#define EXCHANGE_SIZE 16
45
46#define CONTEXT_LIST {r0, r1, r2, r3, EXCHANGE_LR, EXCHANGE_SPSR, r12}
47#define CONTEXT_SIZE 28
48
49#ifdef ARM_MULTILIB_VFP_D32
50  #define VFP_CONTEXT_WITH_ALIGNMENT_SPACE (24 * 8 + 4 + 4)
51#endif
52
53.extern _Thread_Dispatch_disable_level
54
55.extern bsp_interrupt_dispatch
56
57.arm
58.globl _ARMV4_Exception_interrupt
59_ARMV4_Exception_interrupt:
60
61        /* Save exchange registers to exchange area */
62        stmdb   sp, EXCHANGE_LIST
63
64        /* Set exchange registers */
65        mov     EXCHANGE_LR, lr
66        mrs     EXCHANGE_SPSR, SPSR
67        mrs     EXCHANGE_CPSR, CPSR
68        sub     EXCHANGE_INT_SP, sp, #EXCHANGE_SIZE
69
70        /* Switch to SVC mode */
71        orr     EXCHANGE_CPSR, EXCHANGE_CPSR, #0x1
72        msr     CPSR_c, EXCHANGE_CPSR
73
74        /*
75         * Save context.  We save the LR separately because it has to be
76         * restored in SVC mode.  The other registers can be restored in INT
77         * mode.
78         */
79        stmdb   sp!, CONTEXT_LIST
80        stmdb   sp!, {lr}
81
82#ifdef ARM_MULTILIB_VFP_D32
83        /* Save VFP context */
84        sub     sp, #VFP_CONTEXT_WITH_ALIGNMENT_SPACE
85        add     r1, sp, #4
86        vmrs    r0, FPSCR
87        bic     r1, r1, #7
88        vstmia  r1!, {d0-d7}
89        vstmia  r1!, {d16-d31}
90        str     r0, [r1]
91#endif
92
93        /* Remember INT stack pointer */
94        mov     r1, EXCHANGE_INT_SP
95
96        /* Restore exchange registers from exchange area */
97        ldmia   r1, EXCHANGE_LIST
98
99        /* Get interrupt nest level */
100        ldr     r0, =ISR_NEST_LEVEL
101        ldr     r2, [r0]
102
103        /* Switch stack if necessary and save original stack pointer */
104        mov     r3, sp
105        cmp     r2, #0
106        moveq   sp, r1
107        stmdb   sp!, {r3}
108
109        /* Switch to THUMB instructions if necessary */
110        SWITCH_FROM_ARM_TO_THUMB        r1
111
112        /* Increment interrupt nest and thread dispatch disable level */
113        ldr     r1, =_Thread_Dispatch_disable_level
114        ldr     r3, [r1]
115        add     r2, #1
116        add     r3, #1
117        str     r2, [r0]
118        str     r3, [r1]
119
120        /* Call BSP dependent interrupt dispatcher */
121        bl      bsp_interrupt_dispatch
122
123        /* Decrement interrupt nest and thread dispatch disable level */
124        ldr     r0, =ISR_NEST_LEVEL
125        ldr     r1, =_Thread_Dispatch_disable_level
126        ldr     r2, [r0]
127        ldr     r3, [r1]
128        sub     r2, #1
129        sub     r3, #1
130        str     r2, [r0]
131        str     r3, [r1]
132
133        /* Restore stack pointer */
134        SWITCH_FROM_THUMB_TO_ARM
135        ldr     sp, [sp]
136        SWITCH_FROM_ARM_TO_THUMB        r0
137
138        /* Check thread dispatch disable level */
139        cmp     r3, #0
140        bne     thread_dispatch_done
141
142        /* Check context switch necessary */
143        ldr     r0, =DISPATCH_NEEDED
144        ldrb    r1, [r0]
145        cmp     r1, #0
146        beq     thread_dispatch_done
147
148        /* This aligns thread_dispatch_done on a 4 byte boundary */
149#ifdef __thumb__
150        nop
151#endif /* __thumb__ */
152
153do_thread_dispatch:
154
155        /* Thread dispatch */
156        bl      _Thread_Dispatch
157
158thread_dispatch_done:
159
160        /* Switch to ARM instructions if necessary */
161        SWITCH_FROM_THUMB_TO_ARM
162
163#ifdef ARM_MULTILIB_VFP_D32
164        /* Restore VFP context */
165        add     r1, sp, #4
166        bic     r1, r1, #7
167        vldmia  r1!, {d0-d7}
168        vldmia  r1!, {d16-d31}
169        ldr     r0, [r1]
170        add     sp, #VFP_CONTEXT_WITH_ALIGNMENT_SPACE
171        vmsr    FPSCR, r0
172#endif
173
174        /* Restore link register */
175        ldmia   sp!, {lr}
176
177        /*
178         * XXX: Remember and restore stack pointer.  The data on the stack is
179         * still in use.  So the stack is now in an inconsistent state.  The
180         * FIQ handler implementation must not use this area.
181         */
182        mov     r0, sp
183        add     sp, #CONTEXT_SIZE
184
185        /* Get INT mode program status register */
186        mrs     r1, CPSR
187        bic     r1, r1, #0x1
188
189        /* Switch to INT mode */
190        msr     CPSR_c, r1
191
192        /* Save EXCHANGE_LR and EXCHANGE_SPSR registers to exchange area */
193        stmdb   sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
194
195        /* Restore context */
196        ldmia   r0, CONTEXT_LIST
197
198        /* Set return address and program status */
199        mov     lr, EXCHANGE_LR
200        msr     SPSR_fsxc, EXCHANGE_SPSR
201
202        /* Restore EXCHANGE_LR and EXCHANGE_SPSR registers from exchange area */
203        ldmia   sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
204
205        /* Return from interrupt */
206        subs    pc, lr, #4
207
208#endif /* ARM_MULTILIB_ARCH_V4 */
Note: See TracBrowser for help on using the repository browser.