summaryrefslogblamecommitdiffstats
path: root/bsps/powerpc/shared/exceptions/ppc_exc_async_normal.S
blob: 4b318e5e168db500be3a13dc2134105762648ece (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
  
                                                                       

                        
                 





                                                          
                                        





                               

                                       

                             








                               

                          

                                    








                                      
                                                   
 
                      
                        


                                






                            
                                                    
                                 


                                     
                                                     

                                                                




                                                                             
                                 
 
                  
 

                                                        
 
                      
                               

                                                                          

                            




                                                             
             






                                                                               

      












                                                              


                                                               
          

                                                                             
           
                                                                



                                           
                                                                
                                                  


                                                                








                                                                                             
 
                                                   
                                  




                                  
                                                                 




                                                                 



                                                   

                                                                                  
                                                              
                                                          

      


































































                                                             
                                                                        
                                     
                      
                                          
      



                                                                                             




                                          

                                           
                                                
 



                                                
                                                                          

                                                              
                                                


                            
                                         




                                                                                             





                                                                              
                                                        
 

                                                                  



                                                                          

                                                               

                                                                                             
 



                                                                           
                                      





                                                                               

                                                                                             
 



                                                                            


                                   
                                                



                                

                                                                  

                                                              
                                                                               




                                                 
                                                                                    

                       
 


































































                                                             

                                  

                                                              

      
























                                                                               
                                                   







                                                                 
                                                                


                                           
                                                                
                                                                







                                                      
                                                                
                                                                


                                                                              
                                                                









                                                                  

                       
                                                    


                    

                                               
                      

                                             
/*
 * Copyright (c) 2011, 2017 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.org/license/LICENSE.
 */

#include <bspopts.h>
#include <rtems/score/percpu.h>
#include <bsp/vectors.h>

#ifdef PPC_EXC_CONFIG_USE_FIXED_HANDLER

#define SCRATCH_0_REGISTER r0
#define SCRATCH_1_REGISTER r3
#define SCRATCH_2_REGISTER r4
#define SCRATCH_3_REGISTER r5
#define SCRATCH_4_REGISTER r6
#define SCRATCH_5_REGISTER r7
#define SCRATCH_6_REGISTER r8
#define SCRATCH_7_REGISTER r9
#define SCRATCH_8_REGISTER r10
#define SCRATCH_9_REGISTER r11
#define SCRATCH_10_REGISTER r12
#define FRAME_REGISTER r14

#define SCRATCH_0_OFFSET GPR0_OFFSET
#define SCRATCH_1_OFFSET GPR3_OFFSET
#define SCRATCH_2_OFFSET GPR4_OFFSET
#define SCRATCH_3_OFFSET GPR5_OFFSET
#define SCRATCH_4_OFFSET GPR6_OFFSET
#define SCRATCH_5_OFFSET GPR7_OFFSET
#define SCRATCH_6_OFFSET GPR8_OFFSET
#define SCRATCH_7_OFFSET GPR9_OFFSET
#define SCRATCH_8_OFFSET GPR10_OFFSET
#define SCRATCH_9_OFFSET GPR11_OFFSET
#define SCRATCH_10_OFFSET GPR12_OFFSET
#define FRAME_OFFSET PPC_EXC_INTERRUPT_FRAME_OFFSET

#ifdef RTEMS_PROFILING
.macro GET_TIME_BASE REG
#if defined(__PPC_CPU_E6500__)
	mfspr \REG, FSL_EIS_ATBL
#elif defined(ppc8540)
	mfspr	\REG, TBRL
#else /* ppc8540 */
	mftb	\REG
#endif /* ppc8540 */
.endm
#endif /* RTEMS_PROFILING */

	.global	ppc_exc_min_prolog_async_tmpl_normal
	.global ppc_exc_interrupt

ppc_exc_min_prolog_async_tmpl_normal:

	stwu	r1, -PPC_EXC_INTERRUPT_FRAME_SIZE(r1)
	PPC_REG_STORE	SCRATCH_1_REGISTER, SCRATCH_1_OFFSET(r1)
	li	SCRATCH_1_REGISTER, 0xffff8000

	/*
	 * We store the absolute branch target address here.  It will be used
	 * to generate the branch operation in ppc_exc_make_prologue().
	 */
	.int	ppc_exc_interrupt

ppc_exc_interrupt:

	/* Save non-volatile FRAME_REGISTER */
	PPC_REG_STORE	FRAME_REGISTER, FRAME_OFFSET(r1)

#ifdef RTEMS_PROFILING
	/* Get entry instant */
	GET_TIME_BASE	FRAME_REGISTER
	stw	FRAME_REGISTER, PPC_EXC_INTERRUPT_ENTRY_INSTANT_OFFSET(r1)
#endif /* RTEMS_PROFILING */

#ifdef __SPE__
	/* Enable SPE */
	mfmsr	FRAME_REGISTER
	oris	FRAME_REGISTER, FRAME_REGISTER, MSR_SPE >> 16
	mtmsr	FRAME_REGISTER
	isync

	/*
	 * Save high order part of SCRATCH_1_REGISTER here.  The low order part
	 * was saved in the minimal prologue.
	 */
	evmergehi	SCRATCH_1_REGISTER, SCRATCH_1_REGISTER, FRAME_REGISTER
	PPC_REG_STORE	FRAME_REGISTER, GPR3_OFFSET(r1)
#endif

#if defined(PPC_MULTILIB_FPU) || defined(PPC_MULTILIB_ALTIVEC)
	/* Enable FPU and/or AltiVec */
	mfmsr	FRAME_REGISTER
#ifdef PPC_MULTILIB_FPU
	ori	FRAME_REGISTER, FRAME_REGISTER, MSR_FP
#endif
#ifdef PPC_MULTILIB_ALTIVEC
	oris	FRAME_REGISTER, FRAME_REGISTER, MSR_VE >> 16
#endif
	mtmsr	FRAME_REGISTER
	isync
#endif

	/* Move frame pointer to non-volatile FRAME_REGISTER */
	mr	FRAME_REGISTER, r1

	/*
	 * Save volatile registers.  The SCRATCH_1_REGISTER has been saved in
	 * minimum prologue.
	 */
	PPC_GPR_STORE	SCRATCH_0_REGISTER, SCRATCH_0_OFFSET(r1)
#ifdef __powerpc64__
	PPC_GPR_STORE	r2, GPR2_OFFSET(r1)
	LA32	r2, .TOC.
#endif
	PPC_GPR_STORE	SCRATCH_2_REGISTER, SCRATCH_2_OFFSET(r1)
	GET_SELF_CPU_CONTROL	SCRATCH_2_REGISTER
	PPC_GPR_STORE	SCRATCH_3_REGISTER, SCRATCH_3_OFFSET(r1)
	PPC_GPR_STORE	SCRATCH_4_REGISTER, SCRATCH_4_OFFSET(r1)
	PPC_GPR_STORE	SCRATCH_5_REGISTER, SCRATCH_5_OFFSET(r1)
	PPC_GPR_STORE	SCRATCH_6_REGISTER, SCRATCH_6_OFFSET(r1)
	PPC_GPR_STORE	SCRATCH_7_REGISTER, SCRATCH_7_OFFSET(r1)
	PPC_GPR_STORE	SCRATCH_8_REGISTER, SCRATCH_8_OFFSET(r1)
	PPC_GPR_STORE	SCRATCH_9_REGISTER, SCRATCH_9_OFFSET(r1)
	PPC_GPR_STORE	SCRATCH_10_REGISTER, SCRATCH_10_OFFSET(r1)

	/* Load ISR nest level and thread dispatch disable level */
	lwz	SCRATCH_3_REGISTER, PER_CPU_ISR_NEST_LEVEL(SCRATCH_2_REGISTER)
	lwz	SCRATCH_4_REGISTER, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(SCRATCH_2_REGISTER)

	/* Save SRR0, SRR1, CR, XER, CTR, and LR */
	mfsrr0	SCRATCH_0_REGISTER
	mfsrr1	SCRATCH_5_REGISTER
	mfcr	SCRATCH_6_REGISTER
	mfxer	SCRATCH_7_REGISTER
	mfctr	SCRATCH_8_REGISTER
	mflr	SCRATCH_9_REGISTER
	PPC_REG_STORE	SCRATCH_0_REGISTER, SRR0_FRAME_OFFSET(r1)
	PPC_REG_STORE	SCRATCH_5_REGISTER, SRR1_FRAME_OFFSET(r1)
	stw	SCRATCH_6_REGISTER, EXC_CR_OFFSET(r1)
	stw	SCRATCH_7_REGISTER, EXC_XER_OFFSET(r1)
	PPC_REG_STORE	SCRATCH_8_REGISTER, EXC_CTR_OFFSET(r1)
	PPC_REG_STORE	SCRATCH_9_REGISTER, EXC_LR_OFFSET(r1)

#ifdef __SPE__
	/* Save SPEFSCR and ACC */
	mfspr	SCRATCH_0_REGISTER, FSL_EIS_SPEFSCR
	evxor	SCRATCH_5_REGISTER, SCRATCH_5_REGISTER, SCRATCH_5_REGISTER
	evmwumiaa	SCRATCH_5_REGISTER, SCRATCH_5_REGISTER, SCRATCH_5_REGISTER
	stw	SCRATCH_0_REGISTER, PPC_EXC_SPEFSCR_OFFSET(r1)
	evstdd	SCRATCH_5_REGISTER, PPC_EXC_ACC_OFFSET(r1)
#endif

#ifdef PPC_MULTILIB_ALTIVEC
	/* Save volatile AltiVec context */
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(0)
	stvx	v0, r1, SCRATCH_0_REGISTER
	mfvscr	v0
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(1)
	stvx	v1, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(2)
	stvx	v2, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(3)
	stvx	v3, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(4)
	stvx	v4, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(5)
	stvx	v5, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(6)
	stvx	v6, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(7)
	stvx	v7, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(8)
	stvx	v8, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(9)
	stvx	v9, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(10)
	stvx	v10, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(11)
	stvx	v11, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(12)
	stvx	v12, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(13)
	stvx	v13, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(14)
	stvx	v14, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(15)
	stvx	v15, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(16)
	stvx	v16, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(17)
	stvx	v17, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(18)
	stvx	v18, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(19)
	stvx	v19, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VSCR_OFFSET
	stvewx	v0, r1, SCRATCH_0_REGISTER
#endif

#ifdef PPC_MULTILIB_FPU
	/* Save volatile FPU context */
	stfd	f0, PPC_EXC_MIN_FR_OFFSET(0)(r1)
	mffs	f0
	stfd	f1, PPC_EXC_MIN_FR_OFFSET(1)(r1)
	stfd	f2, PPC_EXC_MIN_FR_OFFSET(2)(r1)
	stfd	f3, PPC_EXC_MIN_FR_OFFSET(3)(r1)
	stfd	f4, PPC_EXC_MIN_FR_OFFSET(4)(r1)
	stfd	f5, PPC_EXC_MIN_FR_OFFSET(5)(r1)
	stfd	f6, PPC_EXC_MIN_FR_OFFSET(6)(r1)
	stfd	f7, PPC_EXC_MIN_FR_OFFSET(7)(r1)
	stfd	f8, PPC_EXC_MIN_FR_OFFSET(8)(r1)
	stfd	f9, PPC_EXC_MIN_FR_OFFSET(9)(r1)
	stfd	f10, PPC_EXC_MIN_FR_OFFSET(10)(r1)
	stfd	f11, PPC_EXC_MIN_FR_OFFSET(11)(r1)
	stfd	f12, PPC_EXC_MIN_FR_OFFSET(12)(r1)
	stfd	f13, PPC_EXC_MIN_FR_OFFSET(13)(r1)
	stfd	f0, PPC_EXC_MIN_FPSCR_OFFSET(r1)
#endif

	/* Increment ISR nest level and thread dispatch disable level */
	cmpwi	SCRATCH_3_REGISTER, 0
#ifdef RTEMS_PROFILING
	cmpwi	cr2, SCRATCH_3_REGISTER, 0
#endif
	addi	SCRATCH_3_REGISTER, SCRATCH_3_REGISTER, 1
	addi	SCRATCH_4_REGISTER, SCRATCH_4_REGISTER, 1
	stw	SCRATCH_3_REGISTER, PER_CPU_ISR_NEST_LEVEL(SCRATCH_2_REGISTER)
	stw	SCRATCH_4_REGISTER, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(SCRATCH_2_REGISTER)

	/* Switch stack if necessary */
	mfspr	SCRATCH_0_REGISTER, SPRG1
	iselgt	r1, r1, SCRATCH_0_REGISTER

	/* Call fixed high level handler */
	bl	bsp_interrupt_dispatch
	PPC64_NOP_FOR_LINKER_TOC_POINTER_RESTORE

#ifdef RTEMS_PROFILING
	/* Update profiling data if necessary */
	bne	cr2, .Lprofiling_done
	GET_SELF_CPU_CONTROL	r3
	lwz	r4, PPC_EXC_INTERRUPT_ENTRY_INSTANT_OFFSET(FRAME_REGISTER)
	GET_TIME_BASE	r5
	bl	_Profiling_Outer_most_interrupt_entry_and_exit
	PPC64_NOP_FOR_LINKER_TOC_POINTER_RESTORE
.Lprofiling_done:
#endif /* RTEMS_PROFILING */

	/* Load some per-CPU variables */
	GET_SELF_CPU_CONTROL	SCRATCH_1_REGISTER
	lbz	SCRATCH_0_REGISTER, PER_CPU_DISPATCH_NEEDED(SCRATCH_1_REGISTER)
	lwz	SCRATCH_5_REGISTER, PER_CPU_ISR_DISPATCH_DISABLE(SCRATCH_1_REGISTER)
	lwz	SCRATCH_6_REGISTER, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(SCRATCH_1_REGISTER)
	lwz	SCRATCH_3_REGISTER, PER_CPU_ISR_NEST_LEVEL(SCRATCH_1_REGISTER)

	/*
	 * Switch back to original stack (FRAME_REGISTER == r1 if we are still
	 * on the IRQ stack) and restore FRAME_REGISTER.
	 */
	mr	r1, FRAME_REGISTER
	PPC_REG_LOAD	FRAME_REGISTER, FRAME_OFFSET(r1)

	/* Decrement levels and determine thread dispatch state */
	xori	SCRATCH_0_REGISTER, SCRATCH_0_REGISTER, 1
	or	SCRATCH_0_REGISTER, SCRATCH_0_REGISTER, SCRATCH_5_REGISTER
	subi	SCRATCH_4_REGISTER, SCRATCH_6_REGISTER, 1
	or.	SCRATCH_0_REGISTER, SCRATCH_0_REGISTER, SCRATCH_4_REGISTER
	subi	SCRATCH_3_REGISTER, SCRATCH_3_REGISTER, 1

	/* Store thread dispatch disable and ISR nest levels */
	stw	SCRATCH_4_REGISTER, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(SCRATCH_1_REGISTER)
	stw	SCRATCH_3_REGISTER, PER_CPU_ISR_NEST_LEVEL(SCRATCH_1_REGISTER)

	/*
	 * Check thread dispatch necessary, ISR dispatch disable and thread
	 * dispatch disable level.
	 */
	bne	.Lthread_dispatch_done

	/* Thread dispatch */
.Ldo_thread_dispatch:

	/* Set ISR dispatch disable and thread dispatch disable level to one */
	li	SCRATCH_0_REGISTER, 1
	stw	SCRATCH_0_REGISTER, PER_CPU_ISR_DISPATCH_DISABLE(SCRATCH_1_REGISTER)
	stw	SCRATCH_0_REGISTER, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(SCRATCH_1_REGISTER)

	/*
	 * Call _Thread_Do_dispatch(), this function will enable interrupts.
	 * The r3 is SCRATCH_1_REGISTER.
	 */
	mfmsr	r4
	ori	r4, r4, MSR_EE
	bl	_Thread_Do_dispatch
	PPC64_NOP_FOR_LINKER_TOC_POINTER_RESTORE

	/* Disable interrupts */
	wrteei	0

	/* SCRATCH_1_REGISTER is volatile, we must set it again */
	GET_SELF_CPU_CONTROL	SCRATCH_1_REGISTER

	/* Check if we have to do the thread dispatch again */
	lbz	SCRATCH_0_REGISTER, PER_CPU_DISPATCH_NEEDED(SCRATCH_1_REGISTER)
	cmpwi	SCRATCH_0_REGISTER, 0
	bne	.Ldo_thread_dispatch

	/* We are done with thread dispatching */
	li	SCRATCH_0_REGISTER, 0
	stw	SCRATCH_0_REGISTER, PER_CPU_ISR_DISPATCH_DISABLE(SCRATCH_1_REGISTER)

.Lthread_dispatch_done:

#ifdef PPC_MULTILIB_ALTIVEC
	/* Restore volatile AltiVec context */
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VSCR_OFFSET
	lvewx	v0, r1, SCRATCH_0_REGISTER
	mtvscr	v0
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(0)
	lvx	v0, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(1)
	lvx	v1, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(2)
	lvx	v2, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(3)
	lvx	v3, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(4)
	lvx	v4, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(5)
	lvx	v5, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(6)
	lvx	v6, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(7)
	lvx	v7, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(8)
	lvx	v8, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(9)
	lvx	v9, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(10)
	lvx	v10, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(11)
	lvx	v11, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(12)
	lvx	v12, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(13)
	lvx	v13, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(14)
	lvx	v14, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(15)
	lvx	v15, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(16)
	lvx	v16, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(17)
	lvx	v17, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(18)
	lvx	v18, r1, SCRATCH_0_REGISTER
	li	SCRATCH_0_REGISTER, PPC_EXC_MIN_VR_OFFSET(19)
	lvx	v19, r1, SCRATCH_0_REGISTER
#endif

#ifdef PPC_MULTILIB_FPU
	/* Restore volatile FPU context */
	lfd	f0, PPC_EXC_MIN_FPSCR_OFFSET(r1)
	mtfsf	0xff, f0
	lfd	f0, PPC_EXC_MIN_FR_OFFSET(0)(r1)
	lfd	f1, PPC_EXC_MIN_FR_OFFSET(1)(r1)
	lfd	f2, PPC_EXC_MIN_FR_OFFSET(2)(r1)
	lfd	f3, PPC_EXC_MIN_FR_OFFSET(3)(r1)
	lfd	f4, PPC_EXC_MIN_FR_OFFSET(4)(r1)
	lfd	f5, PPC_EXC_MIN_FR_OFFSET(5)(r1)
	lfd	f6, PPC_EXC_MIN_FR_OFFSET(6)(r1)
	lfd	f7, PPC_EXC_MIN_FR_OFFSET(7)(r1)
	lfd	f8, PPC_EXC_MIN_FR_OFFSET(8)(r1)
	lfd	f9, PPC_EXC_MIN_FR_OFFSET(9)(r1)
	lfd	f10, PPC_EXC_MIN_FR_OFFSET(10)(r1)
	lfd	f11, PPC_EXC_MIN_FR_OFFSET(11)(r1)
	lfd	f12, PPC_EXC_MIN_FR_OFFSET(12)(r1)
	lfd	f13, PPC_EXC_MIN_FR_OFFSET(13)(r1)
#endif

#ifdef __SPE__
	/* Load SPEFSCR and ACC */
	lwz	SCRATCH_3_REGISTER, PPC_EXC_SPEFSCR_OFFSET(r1)
	evldd	SCRATCH_4_REGISTER, PPC_EXC_ACC_OFFSET(r1)
#endif

	/*
	 * We must clear reservations here, since otherwise compare-and-swap
	 * atomic operations with interrupts enabled may yield wrong results.
	 * A compare-and-swap atomic operation is generated by the compiler
	 * like this:
	 *
	 *   .L1:
	 *     lwarx  r9, r0, r3
	 *     cmpw   r9, r4
	 *     bne-   .L2
	 *     stwcx. r5, r0, r3
	 *     bne-   .L1
	 *   .L2:
	 *
	 * Consider the following scenario.  A thread is interrupted right
	 * before the stwcx.  The interrupt updates the value using a
	 * compare-and-swap sequence.  Everything is fine up to this point.
	 * The interrupt performs now a compare-and-swap sequence which fails
	 * with a branch to .L2.  The current processor has now a reservation.
	 * The interrupt returns without further stwcx.  The thread updates the
	 * value using the unrelated reservation of the interrupt.
	 */
	li	SCRATCH_0_REGISTER, FRAME_OFFSET
	stwcx.	SCRATCH_0_REGISTER, r1, SCRATCH_0_REGISTER

	/* Load SRR0, SRR1, CR, XER, CTR, and LR */
	PPC_REG_LOAD	SCRATCH_5_REGISTER, SRR0_FRAME_OFFSET(r1)
	PPC_REG_LOAD	SCRATCH_6_REGISTER, SRR1_FRAME_OFFSET(r1)
	lwz	SCRATCH_7_REGISTER, EXC_CR_OFFSET(r1)
	lwz	SCRATCH_8_REGISTER, EXC_XER_OFFSET(r1)
	PPC_REG_LOAD	SCRATCH_9_REGISTER, EXC_CTR_OFFSET(r1)
	PPC_REG_LOAD	SCRATCH_10_REGISTER, EXC_LR_OFFSET(r1)

	/* Restore volatile registers */
	PPC_GPR_LOAD	SCRATCH_0_REGISTER, SCRATCH_0_OFFSET(r1)
#ifdef __powerpc64__
	PPC_GPR_LOAD	r2, GPR2_OFFSET(r1)
#endif
	PPC_GPR_LOAD	SCRATCH_1_REGISTER, SCRATCH_1_OFFSET(r1)
	PPC_GPR_LOAD	SCRATCH_2_REGISTER, SCRATCH_2_OFFSET(r1)

#ifdef __SPE__
	/* Restore SPEFSCR and ACC */
	mtspr	FSL_EIS_SPEFSCR, SCRATCH_3_REGISTER
	evmra	SCRATCH_4_REGISTER, SCRATCH_4_REGISTER
#endif

	/* Restore volatile registers */
	PPC_GPR_LOAD	SCRATCH_3_REGISTER, SCRATCH_3_OFFSET(r1)
	PPC_GPR_LOAD	SCRATCH_4_REGISTER, SCRATCH_4_OFFSET(r1)

	/* Restore SRR0, SRR1, CR, CTR, XER, and LR plus volatile registers */
	mtsrr0	SCRATCH_5_REGISTER
	PPC_GPR_LOAD	SCRATCH_5_REGISTER, SCRATCH_5_OFFSET(r1)
	mtsrr1	SCRATCH_6_REGISTER
	PPC_GPR_LOAD	SCRATCH_6_REGISTER, SCRATCH_6_OFFSET(r1)
	mtcr	SCRATCH_7_REGISTER
	PPC_GPR_LOAD	SCRATCH_7_REGISTER, SCRATCH_7_OFFSET(r1)
	mtxer	SCRATCH_8_REGISTER
	PPC_GPR_LOAD	SCRATCH_8_REGISTER, SCRATCH_8_OFFSET(r1)
	mtctr	SCRATCH_9_REGISTER
	PPC_GPR_LOAD	SCRATCH_9_REGISTER, SCRATCH_9_OFFSET(r1)
	mtlr	SCRATCH_10_REGISTER
	PPC_GPR_LOAD	SCRATCH_10_REGISTER, SCRATCH_10_OFFSET(r1)

	/* Pop stack */
	addi	r1, r1, PPC_EXC_INTERRUPT_FRAME_SIZE

	/* Return */
	rfi

/* Symbol provided for debugging and tracing */
ppc_exc_interrupt_end:

#endif /* PPC_EXC_CONFIG_USE_FIXED_HANDLER */