Changeset 9db18dd in rtems


Ignore:
Timestamp:
Dec 15, 2009, 3:14:12 PM (11 years ago)
Author:
Thomas Doerfler <Thomas.Doerfler@…>
Branches:
4.10, 4.11, 5, master
Children:
c468f18b
Parents:
3a23218
Message:

add support for ARM11, reimplement nested interrupts

Location:
cpukit/score/cpu/arm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • cpukit/score/cpu/arm/ChangeLog

    r3a23218 r9db18dd  
     12009-12-15      Sebastian Huber <sebastian.huber@embedded-brains.de>
     2
     3        * rtems/score/arm.h: Recognize ARMv5TEJ.
     4        * arm_exc_interrupt.S: The previous implementation was broken.  In
     5        case of a nested interrupt the link register of the INT mode was not
     6        properly restored.  This lead to a major rewrite.  Interrupt
     7        processing is now done in SVC mode.
     8
    192009-10-01      Joel Sherrill <joel.sherrill@oarcorp.com>
    210
  • cpukit/score/cpu/arm/arm_exc_interrupt.S

    r3a23218 r9db18dd  
    1919
    2020/*
    21  * These two non-volatile registers contain the program status for INT and SVC
    22  * mode.  It is important that they are directly accessible in THUMB
    23  * instruction mode.
     21 * The upper EXCHANGE_SIZE bytes of the INT stack area are used for data
     22 * exchange between INT and SVC mode.  Below of this is the actual INT stack.
     23 * The exchange area is only accessed if INT is disabled.
    2424 */
    25 #define MODE_INT r4
    26 #define MODE_SVC r5
    2725
    28 /*
    29  * These three non-volatile registers are used to exchange information between
    30  * INT and SVC mode.
    31  */
    32 #define SCRATCH_0 r6
    33 #define SCRATCH_1 r7
    34 #define SCRATCH_2 r8
     26#define EXCHANGE_LR r4
     27#define EXCHANGE_SPSR r5
     28#define EXCHANGE_CPSR r6
     29#define EXCHANGE_INT_SP r7
    3530
    36 /* List of scratch registers.  They will be saved and restored in INT mode. */
    37 #define SCRATCH_LIST {SCRATCH_0, SCRATCH_1, SCRATCH_2}
     31#define EXCHANGE_LIST {EXCHANGE_LR, EXCHANGE_SPSR, EXCHANGE_CPSR, EXCHANGE_INT_SP}
     32#define EXCHANGE_SIZE 16
    3833
    39 /*
    40  * List of all volatile registers (r0, r1, r2, r3, r12 and lr), registers
    41  * containing the interrupt context (return address in SCRATCH_0 and saved
    42  * program status in SCRATCH_1) and non-volatile registers used for modes
    43  * (MODE_INT and MODE_SVC).  They will be saved and restored in SVC mode.
    44  */
    45 #define TASK_CONTEXT_LIST \
    46         {r0, r1, r2, r3, MODE_INT, MODE_SVC, SCRATCH_0, SCRATCH_1, r12, lr}
     34#define CONTEXT_LIST {r0, r1, r2, r3, EXCHANGE_LR, EXCHANGE_SPSR, r12}
     35#define CONTEXT_SIZE 28
    4736
    48 /*
    49  * List of all volatile registers (r0, r1, r2, r3, r12 and lr) and the saved
    50  * program status (SCRATCH_0 register).  They will be saved and restored in INT
    51  * mode.
    52  */
    53 #define INTERRUPT_CONTEXT_LIST \
    54         {r0, r1, r2, r3, SCRATCH_0, r12, lr}
     37.extern _ISR_Nest_level
     38.extern _ISR_Signals_to_thread_executing
     39.extern _ISR_Thread_dispatch
     40.extern _Thread_Dispatch_disable_level
    5541
    56 .extern _ISR_Thread_dispatch
    57 .extern _ISR_Nest_level
    58 .extern _Thread_Dispatch_disable_level
    5942.extern bsp_interrupt_dispatch
     43
     44.macro SWITCH_FROM_THUMB_TO_ARM
     45#ifdef __thumb__
     46.align 2
     47        bx      pc
     48.arm
     49#endif /* __thumb__ */
     50.endm
     51
     52.macro SWITCH_FROM_ARM_TO_THUMB REG
     53#ifdef __thumb__
     54        add     \REG, pc, #1
     55        bx      \REG
     56.thumb
     57#endif /* __thumb__ */
     58.endm
    6059
    6160.arm
     
    6362arm_exc_interrupt:
    6463
    65         /* Save scratch registers on INT stack */
    66         stmdb   sp!, SCRATCH_LIST
     64        /* Save exchange registers to exchange area */
     65        stmdb   sp, EXCHANGE_LIST
    6766
    68         /* Increment interrupt nest level */
    69         ldr     SCRATCH_0, =_ISR_Nest_level
    70         ldr     SCRATCH_1, [SCRATCH_0]
    71         add     SCRATCH_2, SCRATCH_1, #1
    72         str     SCRATCH_2, [SCRATCH_0]
    73 
    74         /* Branch for nested interrupts */
    75         cmp     SCRATCH_1, #0
    76         bne     nested_interrupt_context_save
    77 
    78         /* Move interrupt context and CPSR to scratch registers */
    79         mov     SCRATCH_0, lr
    80         mrs     SCRATCH_1, spsr
    81         mrs     SCRATCH_2, cpsr
     67        /* Set exchange registers */
     68        mov     EXCHANGE_LR, lr
     69        mrs     EXCHANGE_SPSR, spsr
     70        mrs     EXCHANGE_CPSR, cpsr
     71        sub     EXCHANGE_INT_SP, sp, #EXCHANGE_SIZE
    8272
    8373        /* Switch to SVC mode */
    84         orr     SCRATCH_2, SCRATCH_2, #0x1
    85         msr     cpsr_c, SCRATCH_2
    86 
    87         /* Save context on SVC stack */
    88         stmdb   sp!, TASK_CONTEXT_LIST
    89 
    90         /* Save SVC mode program status to non-volatile register */
    91         mov     MODE_SVC, SCRATCH_2
    92 
    93         /* Save INT mode program status to non-volatile register */
    94         bic     MODE_INT, MODE_SVC, #0x1
    95        
    96         /* Switch to INT mode */
    97         msr     cpsr_c, MODE_INT
    98 
    99         /* Restore scratch registers from INT stack */
    100         ldmia   sp!, SCRATCH_LIST
     74        orr     EXCHANGE_CPSR, EXCHANGE_CPSR, #0x1
     75        msr     cpsr, EXCHANGE_CPSR
    10176
    10277        /*
    103          * At this point the INT stack is in the exception entry state and
    104          * contains no data for us.  The context is saved on the SVC stack.  We
    105          * can easily switch modes via the registers MODE_INT and MODE_SVC
    106          * which are valid through subroutine calls.  We can use all volatile
    107          * registers in both modes.  Note that this comment describes the non
    108          * nested interrupt entry.  For a nested interrupt things are
    109          * different, since we can save everything on the INT stack and there
    110          * is no need to switch modes.
     78         * Save context.  We save the LR separately because it has to be
     79         * restored in SVC mode.  The other registers can be restored in INT
     80         * mode.
    11181         */
     82        stmdb   sp!, CONTEXT_LIST
     83        stmdb   sp!, {lr}
    11284
    113 task_context_save_done:
     85        /* Remember INT stack pointer */
     86        mov     r1, EXCHANGE_INT_SP
     87
     88        /* Restore exchange registers from exchange area */
     89        ldmia   r1, EXCHANGE_LIST
     90
     91        /* Get interrupt nest level */
     92        ldr     r0, =_ISR_Nest_level
     93        ldr     r2, [r0]
     94
     95        /* Switch stack if necessary and save original stack pointer */
     96        mov     r3, sp
     97        cmp     r2, #0
     98        moveq   sp, r1
     99        stmdb   sp!, {r3}
    114100
    115101        /* Switch to THUMB instructions if necessary */
    116 #ifdef __thumb__
    117         add     r0, pc, #1
    118         bx      r0
    119 .thumb
    120 #endif /* __thumb__ */
     102        SWITCH_FROM_ARM_TO_THUMB        r1
    121103
    122         /* Increment thread dispatch disable level */
     104        /* Increment interrupt nest and thread dispatch disable level */
    123105        ldr     r1, =_Thread_Dispatch_disable_level
    124106        ldr     r3, [r1]
    125         add     r3, r3, #1
     107        add     r2, #1
     108        add     r3, #1
     109        str     r2, [r0]
    126110        str     r3, [r1]
    127111
    128         /* Call BSP dependent interrrupt dispatcher */
     112        /* Call BSP dependent interrupt dispatcher */
    129113        bl      bsp_interrupt_dispatch
    130114
     
    134118        ldr     r2, [r0]
    135119        ldr     r3, [r1]
    136         sub     r2, r2, #1
    137         sub     r3, r3, #1
     120        sub     r2, #1
     121        sub     r3, #1
    138122        str     r2, [r0]
    139123        str     r3, [r1]
    140124
    141         /* Switch to ARM instructions if necessary */
     125        /* Restore stack pointer */
     126        SWITCH_FROM_THUMB_TO_ARM
     127        ldr     sp, [sp]
     128        SWITCH_FROM_ARM_TO_THUMB        r0
     129
     130        /* Check thread dispatch disable level */
     131        cmp     r3, #0
     132        bne     thread_dispatch_done
     133
     134        /* Check context switch necessary */
     135        ldr     r0, =_Context_Switch_necessary
     136        ldrb    r1, [r0]
     137        ldr     r0, =_ISR_Signals_to_thread_executing
     138        cmp     r1, #0
     139        bne     do_thread_dispatch
     140
     141        /* Check ISR signals to thread executing */
     142        ldrb    r1, [r0]
     143        cmp     r1, #0
     144        beq     thread_dispatch_done
     145
     146        /* This aligns thread_dispatch_done on a 4 byte boundary */
    142147#ifdef __thumb__
    143 .align 2
    144         bx      pc
    145 .arm
     148        nop
    146149#endif /* __thumb__ */
    147150
    148         /* Branch if we have a nested interrupt */
    149         cmp     r2, #0
    150         bne     nested_interrupt_return
     151do_thread_dispatch:
    151152
    152         /* Branch if thread dispatching is disabled */
    153         cmp     r3, #0
    154         bne     thread_dispatch_done
    155        
    156         /*
    157          * Switch to SVC mode.  It is important to call the thread dispatcher
    158          * in SVC mode since overwise the INT stack may need to store an
    159          * arbitrary number of contexts and it may lead to an invalid order of
    160          * stack operations.
    161          */
    162         msr     cpsr_c, MODE_SVC
     153        /* Clear ISR signals to thread executing */
     154        strb    r3, [r0]
    163155
    164         /* Call thread dispatcher */
    165 #ifdef __thumb__
    166         ldr     r0, =_ISR_Thread_dispatch
    167         mov     lr, pc
    168         bx      r0
    169 .thumb
    170         bx      pc
    171         nop
    172 .arm
    173 #else
    174         bl      _ISR_Thread_dispatch
    175 #endif
    176 
    177         /* Switch to INT mode */
    178         msr     cpsr_c, MODE_INT
     156        /* Thread dispatch */
     157        bl      _Thread_Dispatch
    179158
    180159thread_dispatch_done:
    181160
    182         /* Save scratch registers on INT stack */
    183         stmdb   sp!, SCRATCH_LIST
     161        /* Switch to ARM instructions if necessary */
     162        SWITCH_FROM_THUMB_TO_ARM
    184163
    185         /* Switch to SVC mode */
    186         msr     cpsr_c, MODE_SVC
     164        /* Restore link register */
     165        ldmia   sp!, {lr}
    187166
    188         /* Move INT mode program status to scratch register */
    189         mov     SCRATCH_2, MODE_INT
     167        /*
     168         * XXX: Remember and restore stack pointer.  The data on the stack is
     169         * still in use.  So the stack is now in an inconsistent state.  The
     170         * FIQ handler implementation must not use this area.
     171         */
     172        mov     r0, sp
     173        add     sp, #CONTEXT_SIZE
    190174
    191         /* Restore context from SVC stack */
    192         ldmia   sp!, TASK_CONTEXT_LIST
     175        /* Get INT mode program status register */
     176        mrs     r1, cpsr
     177        bic     r1, r1, #0x1
    193178
    194179        /* Switch to INT mode */
    195         msr     cpsr_c, SCRATCH_2
     180        msr     cpsr, r1
    196181
    197         /* Restore interrupt context */
    198         mov     lr, SCRATCH_0
    199         msr     spsr, SCRATCH_1
     182        /* Save EXCHANGE_LR and EXCHANGE_SPSR registers to exchange area */
     183        stmdb   sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
    200184
    201         /* Restore scratch registers from INT stack */
    202         ldmia   sp!, SCRATCH_LIST
     185        /* Restore context */
     186        ldmia   r0, CONTEXT_LIST
     187
     188        /* Set return address and program status */
     189        mov     lr, EXCHANGE_LR
     190        msr     spsr, EXCHANGE_SPSR
     191
     192        /* Restore EXCHANGE_LR and EXCHANGE_SPSR registers from exchange area */
     193        ldmia   sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
    203194
    204195        /* Return from interrupt */
    205196        subs    pc, lr, #4
    206 
    207 nested_interrupt_context_save:
    208 
    209         /* Move saved program status register to scratch register */
    210         mrs     SCRATCH_0, spsr
    211 
    212         /* Save context on INT stack */
    213         stmdb   sp!, INTERRUPT_CONTEXT_LIST
    214 
    215         b       task_context_save_done
    216 
    217 nested_interrupt_return:
    218 
    219         /* Restore context from INT stack */
    220         ldmia   sp!, INTERRUPT_CONTEXT_LIST
    221 
    222         /* Restore saved program status register */
    223         msr     spsr, SCRATCH_0
    224 
    225         /* Restore scratch registers from INT stack */
    226         ldmia   sp!, SCRATCH_LIST
    227 
    228         /* Return from interrupt */
    229         subs    pc, lr, #4
  • cpukit/score/cpu/arm/rtems/score/arm.h

    r3a23218 r9db18dd  
    5151#  define CPU_MODEL_NAME  "ARMv5TE"
    5252
     53#elif defined(__ARM_ARCH_5TEJ__)
     54#  define CPU_MODEL_NAME  "ARMv5TEJ"
     55
    5356#elif defined(__ARM_ARCH_6J__)
    5457#  define CPU_MODEL_NAME  "ARMv6J"
Note: See TracChangeset for help on using the changeset viewer.