summaryrefslogblamecommitdiffstats
path: root/cpukit/score/cpu/arm/arm_exc_interrupt.S
blob: 3789309715b0fc9472007e171de1a49fae963327 (plain) (tree)
1
2
3
4
5
6
7
8
9


        
                    
  



                                                        






                                                                      






                                                          


                                                                             
   
 



                    
                      
                               
 

                           


                        
                          
 

                                                                                  
 



                                                                                        
 



                                                           




                                                                
 



                                                                
 
    

                                 
 

                                                      
 

                                    

                                   
                                                   

                                
                                                  
                                     
 






                                                                            
 










                                                     

                                                      
 

                                        
 

                                                           
 
                                      
                                                               
 




                                                                       

                                                       
                                          
 
                                                                        
                                                                              

                      

                                                                              
 
                                                     


                                                                        

                                                                              

                      

                                                                              
 



                                          
 
                                                 

                                    
 
                                            
                                                                

                                    
 



                                                                   
 

                                
 
                     
 

                                                     
 










                                                     

                                   
 






                                                                             
 
                                                  
                        
                            
 
                                
                          
 

                                                                           
 

                                
 

                                                   
                                        
 

                                                                                


                                   

                                 
/**
 * @file
 *
 * @ingroup ScoreCPU
 *
 * @brief ARM interrupt exception prologue and epilogue.
 */

/*
 * Copyright (c) 2009-2013 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Dornierstr. 4
 *  82178 Puchheim
 *  Germany
 *  <rtems@embedded-brains.de>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.com/license/LICENSE.
 */

/*
 * The upper EXCHANGE_SIZE bytes of the INT stack area are used for data
 * exchange between INT and SVC mode.  Below of this is the actual INT stack.
 * The exchange area is only accessed if INT is disabled.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <rtems/asm.h>
#include <rtems/score/percpu.h>

#ifdef ARM_MULTILIB_ARCH_V4

#define EXCHANGE_LR r4
#define EXCHANGE_SPSR r5
#define EXCHANGE_CPSR r6
#define EXCHANGE_INT_SP r8

#define EXCHANGE_LIST {EXCHANGE_LR, EXCHANGE_SPSR, EXCHANGE_CPSR, EXCHANGE_INT_SP}
#define EXCHANGE_SIZE 16

#define SELF_CPU_CONTROL r7

#define CONTEXT_LIST {r0, r1, r2, r3, EXCHANGE_LR, EXCHANGE_SPSR, SELF_CPU_CONTROL, r12}
#define CONTEXT_SIZE 32

#ifdef ARM_MULTILIB_VFP_D32
  #define VFP_CONTEXT_WITH_ALIGNMENT_SPACE (24 * 8 + 4 + 4)
#endif

.macro GET_SELF_CPU_CONTROL REG, TMP
	ldr	\REG, =_Per_CPU_Information
#ifdef RTEMS_SMP
	/* Use ARMv7 Multiprocessor Affinity Register (MPIDR) */
	mrc	p15, 0, \TMP, c0, c0, 5

	and	\TMP, \TMP, #0xff
	add	\REG, \REG, \TMP, asl #PER_CPU_CONTROL_SIZE_LOG2
#endif
.endm

.arm
.globl _ARMV4_Exception_interrupt
_ARMV4_Exception_interrupt:

	/* Save exchange registers to exchange area */
	stmdb	sp, EXCHANGE_LIST

	/* Set exchange registers */
	mov	EXCHANGE_LR, lr
	mrs	EXCHANGE_SPSR, SPSR
	mrs	EXCHANGE_CPSR, CPSR
	sub	EXCHANGE_INT_SP, sp, #EXCHANGE_SIZE

	/* Switch to SVC mode */
	orr	EXCHANGE_CPSR, EXCHANGE_CPSR, #0x1
	msr	CPSR_c, EXCHANGE_CPSR

	/*
	 * Save context.  We save the LR separately because it has to be
	 * restored in SVC mode.  The other registers can be restored in INT
	 * mode.
	 */
	stmdb	sp!, CONTEXT_LIST
	stmdb	sp!, {lr}

#ifdef ARM_MULTILIB_VFP_D32
	/* Save VFP context */
	sub	sp, #VFP_CONTEXT_WITH_ALIGNMENT_SPACE
	add	r1, sp, #4
	vmrs	r0, FPSCR
	bic	r1, r1, #7
	vstmia	r1!, {d0-d7}
	vstmia	r1!, {d16-d31}
	str	r0, [r1]
#endif

	/* Get per-CPU control of current processor */
	GET_SELF_CPU_CONTROL	SELF_CPU_CONTROL, r1

	/* Remember INT stack pointer */
	mov	r1, EXCHANGE_INT_SP

	/* Restore exchange registers from exchange area */
	ldmia	r1, EXCHANGE_LIST

	/* Get interrupt nest level */
	ldr	r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL]

	/* Switch stack if necessary and save original stack pointer */
	mov	r3, sp
	cmp	r2, #0
	moveq	sp, r1
	stmdb	sp!, {r3}

	/* Switch to THUMB instructions if necessary */
	SWITCH_FROM_ARM_TO_THUMB        r1

	/* Increment interrupt nest and thread dispatch disable level */
	ldr	r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
	add	r2, #1
	add	r3, #1
	str	r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL]
	str	r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]

	/* Call BSP dependent interrupt dispatcher */
	bl	bsp_interrupt_dispatch

	/* Decrement interrupt nest and thread dispatch disable level */
	ldr	r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL]
	ldr	r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]
	sub	r2, #1
	sub	r3, #1
	str	r2, [SELF_CPU_CONTROL, #PER_CPU_ISR_NEST_LEVEL]
	str	r3, [SELF_CPU_CONTROL, #PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL]

	/* Restore stack pointer */
	SWITCH_FROM_THUMB_TO_ARM
	ldr	sp, [sp]
	SWITCH_FROM_ARM_TO_THUMB	r0

	/* Check thread dispatch disable level */
	cmp	r3, #0
	bne	thread_dispatch_done

	/* Check context switch necessary */
	ldrb	r1, [SELF_CPU_CONTROL, #PER_CPU_DISPATCH_NEEDED]
	cmp	r1, #0
	beq	thread_dispatch_done

        /* This aligns thread_dispatch_done on a 4 byte boundary */
#ifdef __thumb__
	nop
#endif /* __thumb__ */

	/* Thread dispatch */
	bl	_Thread_Dispatch

thread_dispatch_done:

	/* Switch to ARM instructions if necessary */
	SWITCH_FROM_THUMB_TO_ARM

#ifdef ARM_MULTILIB_VFP_D32
	/* Restore VFP context */
	add	r1, sp, #4
	bic	r1, r1, #7
	vldmia	r1!, {d0-d7}
	vldmia	r1!, {d16-d31}
	ldr	r0, [r1]
	add	sp, #VFP_CONTEXT_WITH_ALIGNMENT_SPACE
	vmsr	FPSCR, r0
#endif

	/* Restore link register */
	ldmia	sp!, {lr}

	/*
	 * XXX: Remember and restore stack pointer.  The data on the stack is
	 * still in use.  So the stack is now in an inconsistent state.  The
	 * FIQ handler implementation must not use this area.
	 */
	mov	r0, sp
	add	sp, #CONTEXT_SIZE

	/* Get INT mode program status register */
	mrs	r1, CPSR
	bic	r1, r1, #0x1

	/* Switch to INT mode */
	msr	CPSR_c, r1

	/* Save EXCHANGE_LR and EXCHANGE_SPSR registers to exchange area */
	stmdb	sp!, {EXCHANGE_LR, EXCHANGE_SPSR}

	/* Restore context */
	ldmia	r0, CONTEXT_LIST

	/* Set return address and program status */
	mov	lr, EXCHANGE_LR
	msr	SPSR_fsxc, EXCHANGE_SPSR

	/* Restore EXCHANGE_LR and EXCHANGE_SPSR registers from exchange area */
	ldmia	sp!, {EXCHANGE_LR, EXCHANGE_SPSR}

	/* Return from interrupt */
	subs	pc, lr, #4

#endif /* ARM_MULTILIB_ARCH_V4 */