##========================================================================== ## ## vectors.S ## ## PowerPC exception vectors ## ##========================================================================== ## ####ECOSGPLCOPYRIGHTBEGIN#### ## ------------------------------------------- ## This file is part of eCos, the Embedded Configurable Operating System. ## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. ## ## eCos is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free ## Software Foundation; either version 2 or (at your option) any later ## version. ## ## eCos is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## for more details. ## ## You should have received a copy of the GNU General Public License ## along with eCos; if not, write to the Free Software Foundation, Inc., ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ## ## As a special exception, if other files instantiate templates or use ## macros or inline functions from this file, or you compile this file ## and link it with other works to produce a work based on this file, ## this file does not by itself cause the resulting work to be covered by ## the GNU General Public License. However the source code for this file ## must still be made available in accordance with section (3) of the GNU ## General Public License v2. ## ## This exception does not invalidate any other reasons why a work based ## on this file might be covered by the GNU General Public License. ## ------------------------------------------- ## ####ECOSGPLCOPYRIGHTEND#### ##========================================================================== #######DESCRIPTIONBEGIN#### ## ## Author(s): nickg, jskov ## Contributors: nickg, jskov ## Date: 1999-02-20 ## Purpose: PowerPC exception vectors ## Description: This file defines the code placed into the exception ## vectors. It also contains the first level default VSRs ## that save and restore state for both exceptions and ## interrupts. ## ######DESCRIPTIONEND#### ## ##========================================================================== #=========================================================================== # # The PowerPC exception handling has changed as of version 1.3.1. # The primary motivation for rewriting the code was to bring it more # in line with the other HALs, in particular to allow a RAM application # to cleanly take over only a subset of vectors from a running ROM # monitor. # # GDB stubs (and CygMon, should it be ported to PPC) copies # exception vector entry handler code to address 0. These vector entry # handlers (defined by the exception_vector macro below) compute # a vector index into the hal_vsr_table, fetch the pointer, and # jump to the HAL vector service routine (VSR). # # The hal_vsr_table is located immediately after the vector # handlers (at address 0x3000), allowing RAM applications to # change VSRs as necessary, while still keeping desired ROM # monitor functionality available for debugging. # # ROM applications can still be configured to leave the vector entry # handlers at 0xff000000, but there is at the moment no # provision for reclaiming the reserved vector space in RAM to # application usage. # # RAM applications can also be configured to provide exception # handlers which are copied to address 0 on startup, thus taking # full control of the target. # # # Default configuration is for RAM applications to rely on an # existing ROM monitor to provide debugging functionality, and # for ROM applications to copy vectors to address 0. # # # Unfortunately the new exception scheme is not compatible with the # old scheme. Stubs and applications must be compiled using the same # scheme (i.e., old binaries will not run with new stubs, and new # binaries will not run with old stubs). # #=========================================================================== #include #ifdef CYGPKG_KERNEL #include // CYGPKG_KERNEL_INSTRUMENT #endif #define CYGARC_HAL_COMMON_EXPORT_CPU_MACROS #include #=========================================================================== // .file "vectors.S" .extern hal_interrupt_data .extern hal_interrupt_handlers .extern hal_interrupt_objects .extern hal_vsr_table .extern cyg_hal_invoke_constructors .extern cyg_instrument .extern cyg_start .extern hal_IRQ_init .extern hal_MMU_init .extern hal_enable_caches .extern hal_hardware_init .extern initialize_stub .extern __bss_start .extern __bss_end .extern __sbss_start .extern __sbss_end #=========================================================================== # MSR initialization value # zero all bits except: # FP = floating point available # ME = machine check enabled # IP = vectors at 0xFFFxxxxx (ROM startup only) # IR = instruction address translation # DR = data address translation # RI = recoverable interrupt #define CYG_MSR_COMMON (MSR_FP | MSR_ME | MSR_RI) #if (CYGHWR_HAL_POWERPC_VECTOR_BASE == 0xfff00000) # define IP_BIT MSR_IP #else # define IP_BIT 0 #endif #ifdef CYGHWR_HAL_POWERPC_ENABLE_MMU # define IR_DR_BITS (MSR_IR | MSR_DR) #else # define IR_DR_BITS 0 #endif #define CYG_MSR (CYG_MSR_COMMON | IP_BIT | IR_DR_BITS) # Include variant macros after MSR definition. #include #include #=========================================================================== # If the following option is enabled, we only save registers up to R12. # The PowerPC ABI defines registers 13..31 as callee saved and thus we do # not need to save them when calling C functions. #ifdef CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT # define MAX_SAVE_REG 12 #else # define MAX_SAVE_REG 31 #endif #if defined(CYGHWR_HAL_POWERPC_NEED_VECTORS) #=========================================================================== # Start by defining the exceptions vectors that must be placed at # locations 0xFFF00000 or 0x00000000. The following code will normally # be located at 0xFFF00000 in the ROM. It may optionally be copied out # to 0x00000000 if we want to use the RAM vectors. For this reason this code # MUST BE POSITION INDEPENDENT. .section ".vectors","ax" #--------------------------------------------------------------------------- # Macros for generating an exception vector service routine # Reset vector macro .macro reset_vector name .p2align CYGHWR_HAL_POWERPC_VECTOR_ALIGNMENT .globl __exception_\name __exception_\name: #ifdef CYGSEM_HAL_POWERPC_RESET_USES_JUMP bl _start #else lwi r3,_start mtlr r3 blr #endif .endm # Generic vector macro .macro exception_vector name .p2align CYGHWR_HAL_POWERPC_VECTOR_ALIGNMENT .globl __exception_\name __exception_\name: mtspr SPRG1,r3 # stash some work registers away mtspr SPRG2,r4 mtspr SPRG3,r5 mfcr r4 # stash CR li r5,__exception_\name-rom_vectors # load low half of vector addr srwi r5,r5,(CYGHWR_HAL_POWERPC_VECTOR_ALIGNMENT-2) # shift right by alignment-2 lwi r3,hal_vsr_table # table base lwzx r3,r3,r5 # address of vsr mflr r5 # save link register mtlr r3 # put vsr address into it li r3,__exception_\name-rom_vectors # reload low half of vector addr blr # go to common code .endm #--------------------------------------------------------------------------- # Define the exception vectors. // Some platforms won't let us put the vector code just where we want // This macro introduces some lattitude in vector placement #ifdef CYG_HAL_FUDGE_VECTOR_ALIGNMENT hal_fudge_vector_alignment #endif hal_fixed_vectors rom_vectors: # These are the architecture defined vectors that # are always present. #ifdef CYG_HAL_RESERVED_VECTOR_00000 hal_reserved_vector_00000 #else exception_vector reserved_00000 #endif reset_vector reset exception_vector machine_check exception_vector data_storage exception_vector instruction_storage exception_vector external exception_vector alignment exception_vector program exception_vector floatingpoint_unavailable exception_vector decrementer exception_vector reserved_00a00 exception_vector reserved_00b00 exception_vector system_call exception_vector trace exception_vector floatingpoint_assist exception_vector reserved_00f00 #if defined(CYGHWR_HAL_POWERPC_BOOK_E) # Book E defines some extra vectors exception_vector critical_input exception_vector ap_unavailable exception_vector interval_timer exception_vector watchdog exception_vector data_tlb_miss exception_vector instruction_tlb_miss exception_vector debug #endif # Variants may define extra vectors. hal_extra_vectors rom_vectors_end: #else // CYGHWR_HAL_POWERPC_NEED_VECTORS # When vectors are not included this is the primary entry point. .globl __exception_reset __exception_reset: lwi r3,_start mtlr r3 blr #endif // CYGHWR_HAL_POWERPC_NEED_VECTORS #=========================================================================== # Real startup code. We jump here from the various reset vectors to set up # the world. .text .globl _start _start: # Initialize CPU to a post-reset state, ensuring the ground doesn''t # shift under us while we try to set things up. hal_cpu_init # Set up global offset table lwi r2,_GLOBAL_OFFSET_TABLE_ # set up time base register to zero xor r3,r3,r3 mtspr TBL_W,r3 xor r4,r4,r4 mtspr TBU_W,r4 # Call platform specific hardware initialization # This may include memory controller initialization. It is not # safe to access RAM until after this point. bl hal_hardware_init # this is platform dependent .globl _hal_hardware_init_done _hal_hardware_init_done: hal_vectors_init # set up stack lwi sp,__interrupt_stack mtspr SPRG0,sp # save in sprg0 for later use # Set up exception handlers and VSR table, taking care not to # step on any ROM monitor''s toes. hal_mon_init #if defined(CYG_HAL_STARTUP_ROM) # Copy data from ROM to ram lwi r3,__rom_data_start # r3 = rom start lwi r4,__ram_data_start # r4 = ram start lwi r5,__ram_data_end # r5 = ram end cmplw r4,r5 # skip if no data beq 2f sub r5,r5,r4 # compute number of words to copy srwi r5,r5,2 mtctr r5 subi r3,r3,4 subi r4,r4,4 1: lwzu r0,4(r3) # get word from ROM stwu r0,4(r4) # store in RAM bdnz 1b 2: #endif # clear BSS lwi r3,__bss_start # r3 = start lwi r4,__bss_end # r4 = end li r0,0 # r0 = 0 cmplw r3,r4 # skip if no bss beq 2f sub r4,r4,r3 # compute number of words to clear srwi r4,r4,2 mtctr r4 subi r3,r3,4 1: stwu r0,4(r3) # store zero & increment pointer bdnz 1b 2: # clear SBSS lwi r3,__sbss_start # r3 = start lwi r4,__sbss_end # r4 = end cmplw r3,r4 # skip if no sbss beq 2f sub r4,r4,r3 # compute number of words to clear srwi r4,r4,2 mtctr r4 subi r3,r3,4 1: stwu r0,4(r3) # store zero & increment pointer bdnz 1b 2: # It is now safe to call C functions which may rely on initialized # data. # Set up stack for calls to C code. subi sp,sp,12 # make space on stack li r0,0 stw r0,0(sp) # clear back chain stw r0,8(sp) # zero return pc stwu sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame # Variant HALs may need to do something special before we continue bl hal_variant_init # Platform initialization bl hal_platform_init # MMU and cache are controlled by the same option since caching # on the PPC [typically] does not make sense without the MMU to mark # regions which should not be cached. #ifdef CYGHWR_HAL_POWERPC_ENABLE_MMU # Initialize MMU. bl hal_MMU_init # Enable MMU (if desired) so we can safely enable caches. lwi r3,CYG_MSR # interrupts enabled later sync mtmsr r3 sync # Enable caches bl hal_enable_caches #endif // CYGHWR_HAL_POWERPC_ENABLE_MMU # set up platform specific interrupt environment bl hal_IRQ_init # call c++ constructors bl cyg_hal_invoke_constructors #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS bl initialize_stub #endif #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \ || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT) .extern hal_ctrlc_isr_init bl hal_ctrlc_isr_init #endif bl cyg_start # call cyg_start 9: b 9b # if we return, loop #--------------------------------------------------------------------------- # This code handles the common part of all exception handlers. # It saves the machine state onto the stack and then calls # a "C" routine to do the rest of the work. This work may result # in thread switches, and changes to the saved state. When we return # here the saved state is restored and execution is continued. .text .globl cyg_hal_default_exception_vsr cyg_hal_default_exception_vsr: # We come here with all register containing their # pre-exception values except: # R3 = ls 16 bits of vector address # R4 = saved CR # R5 = saved LR # LR = VSR address # SPRG1 = old R3 # SPRG2 = old R4 # SPRG3 = old R5 # SRR0 = old PC # SRR1 = old MSR and the exception cause (the POW state is lost!) subi sp,sp,CYGARC_PPC_EXCEPTION_DECREMENT # leave space for registers and # a safety margin #ifdef CYGPKG_HAL_POWERPC_PPC40x // The caches on this processor are always enabled when the MMU is on // (and disabled when off). Thus we need to be careful about cache // polution and staleness when changing the MMU state. // At this point, the MMU is off due to the exception. We need to // flush the part of the cache which may be touched before the MMU // is reenabled so that memory will be consistent when that happens. // Of course, this is complicated by the fact that there are no "free" // registers at this point in the code. dcbf 0,sp // Flushes first line stw r3,0(sp) // This is now safe li r3,CYGARC_PPCREG_VECTOR // Flush lines which will be changed dcbf r3,sp li r3,CYGARC_PPCREG_CR dcbf r3,sp li r3,CYGARC_PPCREG_LR dcbf r3,sp lwz r3,0(sp) // Restore register #endif # First, save away some registers stw r3,CYGARC_PPCREG_VECTOR(sp) # stash vector stw r4,CYGARC_PPCREG_CR(sp) # stash CR stw r5,CYGARC_PPCREG_LR(sp) # stash LR # Save exception PC and MSR mfsrr0 r3 stw r3,CYGARC_PPCREG_PC(sp) mfsrr1 r3 stw r3,CYGARC_PPCREG_MSR(sp) cyg_hal_default_exception_vsr_common: #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS # Mark this frame as an Exception frame lwi r3,0xDDDDDDE0 stw r3,CYGARC_PPCREG_WALL_HEAD(sp) lwi r3,0xDDDDDDE1 stw r3,CYGARC_PPCREG_WALL_TAIL(sp) #endif # Enable MMU & interrupt/FPU environment (as configured) lwi r3,CYG_MSR sync mtmsr r3 sync mfspr r3,SPRG1 # save original R3 stw r3,CYGARC_PPCREG_REGS+3*4(sp) mfspr r4,SPRG2 # save original R4 stw r4,CYGARC_PPCREG_REGS+4*4(sp) mfspr r5,SPRG3 # save original R5 stw r5,CYGARC_PPCREG_REGS+5*4(sp) stw r0,CYGARC_PPCREG_REGS+0*4(sp) # save R0 stw r2,CYGARC_PPCREG_REGS+2*4(sp) # save R2 mr r3,sp # recreate original SP addi r3,r3,CYGARC_PPC_EXCEPTION_DECREMENT stw r3,CYGARC_PPCREG_REGS+1*4(sp) # and save it in state # Save registers r6..r12/r31 .set _reg,6 .rept MAX_SAVE_REG+1-6 stw _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp) .set _reg,_reg+1 .endr # Save registers used in vsr (r14+r15) stw r14,(CYGARC_PPCREG_REGS+14*4)(sp) stw r15,(CYGARC_PPCREG_REGS+15*4)(sp) # get remaining family CPU registers mfxer r3 mfctr r4 # and store them stw r3,CYGARC_PPCREG_XER(sp) stw r4,CYGARC_PPCREG_CTR(sp) # Save variant registers hal_variant_save sp # Save FPU registers hal_fpu_save sp # The entire CPU state is now stashed on the stack, # call into C to do something with it. mr r3,sp # R3 = register dump subi sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame li r0,0 # R0 = 0 stw r0,0(sp) # backchain = 0 stw r0,8(sp) # return pc = 0 stwu sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame # where C code can save LR lwi r5,restore_state # get return link mtlr r5 # to link register .extern cyg_hal_exception_handler b cyg_hal_exception_handler # call C code, r3 = registers # When the call returns it will go to restore_state below. #if defined(CYGHWR_HAL_POWERPC_BOOK_E) ##-------------------------------------------------------------------------- ## Critical exception handling code. ## ## Book E processors save the old PC and MSR in CSRR0/1 for certain ## exceptions. This VSR saves the values from these registers before ## branching to the common VSR code. .globl cyg_hal_default_critical_exception_vsr cyg_hal_default_critical_exception_vsr: # We come here with all register containing their # pre-exception values except: # R3 = ls 16 bits of vector address # R4 = saved CR # R5 = saved LR # LR = VSR address # SPRG1 = old R3 # SPRG2 = old R4 # SPRG3 = old R5 # CSRR0 = old PC # CSRR1 = old MSR and the exception cause subi sp,sp,CYGARC_PPC_EXCEPTION_DECREMENT # leave space for registers and # a safety margin # First, save away some registers stw r3,CYGARC_PPCREG_VECTOR(sp) # stash vector stw r4,CYGARC_PPCREG_CR(sp) # stash CR stw r5,CYGARC_PPCREG_LR(sp) # stash LR # Save exception PC and MSR mfspr r3,58 stw r3,CYGARC_PPCREG_PC(sp) mfspr r3,59 stw r3,CYGARC_PPCREG_MSR(sp) b cyg_hal_default_exception_vsr_common #endif ##-------------------------------------------------------------------------- ## The following macros are defined depending on whether the Interrupt ## system is using isr tables or chaining, and depending on the interrupt ## controller in the system. #ifndef CYGPKG_HAL_POWERPC_INTC_DEFINED ## This is the simple version. No interrupt controller, CYGARC_PPCREG_VECTOR ## is updated with the decoded interrupt vector. Isr tables/chaining ## use same interrupt decoder. ## Bit 21 biffers between decrementer (0) and external (1). # decode the interrupt .macro hal_intc_decode dreg,state lwz \dreg,CYGARC_PPCREG_VECTOR(\state) # retrieve vector number, rlwinm \dreg,\dreg,22,31,31 # isolate bit 21 and update stw \dreg,CYGARC_PPCREG_VECTOR(\state) # vector in state frame. slwi \dreg,\dreg,2 # convert to word offset. .endm #endif // CYGPKG_HAL_POWERPC_INTC_DEFINED #--------------------------------------------------------------------------- # Common interrupt handling code. .globl cyg_hal_default_interrupt_vsr cyg_hal_default_interrupt_vsr: # We come here with all register containing their # pre-exception values except: # R3 = ls 16 bits of vector address # R4 = saved CR # R5 = saved LR # LR = VSR address # SPRG1 = old R3 # SPRG2 = old R4 # SPRG3 = old R5 # SRR0 = old PC # SRR1 = old MSR subi sp,sp,CYGARC_PPC_EXCEPTION_DECREMENT # leave space for registers and # a safety margin #ifdef CYGPKG_HAL_POWERPC_PPC40x // The caches on this processor are always enabled when the MMU is on // (and disabled when off). Thus we need to be careful about cache // polution and staleness when changing the MMU state. // At this point, the MMU is off due to the exception. We need to // flush the part of the cache which may be touched before the MMU // is reenabled so that memory will be consistent when that happens. // Of course, this is complicated by the fact that there are no "free" // registers at this point in the code. dcbf 0,sp // Flushes first line stw r3,0(sp) // This is now safe li r3,CYGARC_PPCREG_VECTOR // Flush lines which will be changed dcbf r3,sp li r3,CYGARC_PPCREG_CR dcbf r3,sp li r3,CYGARC_PPCREG_LR dcbf r3,sp lwz r3,0(sp) // Restore register #endif stw r3,CYGARC_PPCREG_VECTOR(sp) # stash vector stw r4,CYGARC_PPCREG_CR(sp) # stash CR stw r5,CYGARC_PPCREG_LR(sp) # stash LR # Save exception PC and MSR mfsrr0 r3 stw r3,CYGARC_PPCREG_PC(sp) mfsrr1 r3 stw r3,CYGARC_PPCREG_MSR(sp) cyg_hal_default_interrupt_vsr_common: #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS # Mark this frame as an interrupt frame lwi r3,0xDDDDDD10 stw r3,CYGARC_PPCREG_WALL_HEAD(sp) lwi r3,0xDDDDDD11 stw r3,CYGARC_PPCREG_WALL_TAIL(sp) #endif # Enable MMU & interrupt/FPU environment as configured lwi r3,CYG_MSR sync mtmsr r3 sync mfspr r3,SPRG1 # save original R3 stw r3,CYGARC_PPCREG_REGS+3*4(sp) mfspr r4,SPRG2 # save original R4 stw r4,CYGARC_PPCREG_REGS+4*4(sp) mfspr r5,SPRG3 # save original R5 stw r5,CYGARC_PPCREG_REGS+5*4(sp) stw r0,CYGARC_PPCREG_REGS+0*4(sp) # save R0 stw r2,CYGARC_PPCREG_REGS+2*4(sp) # save R2 mr r3,sp # recreate original SP addi r3,r3,CYGARC_PPC_EXCEPTION_DECREMENT stw r3,CYGARC_PPCREG_REGS+1*4(sp) # and save it in state # Save registers r6..r12/r31 .set _reg,6 .rept MAX_SAVE_REG+1-6 stw _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp) .set _reg,_reg+1 .endr # Save registers used in vsr (r14+r15) stw r14,CYGARC_PPCREG_REGS+14*4(sp) stw r15,CYGARC_PPCREG_REGS+15*4(sp) # get remaining family CPU registers mfxer r3 mfctr r4 # and store them stw r3,CYGARC_PPCREG_XER(sp) stw r4,CYGARC_PPCREG_CTR(sp) # Save variant registers hal_variant_save sp # Save FPU registers hal_fpu_save sp # The entire CPU state is now stashed on the stack, # increment the scheduler lock and call the ISR # for this vector. #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT .extern cyg_scheduler_sched_lock lwi r3,cyg_scheduler_sched_lock lwz r4,0(r3) addi r4,r4,1 stw r4,0(r3) #endif mr r14,sp # r14 = register dump #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK lwi r3,__interrupt_stack # stack top lwi r4,__interrupt_stack_base # stack base sub. r5,sp,r4 # sp - base blt 1f # if < 0 - not on istack sub. r5,r3,sp # top - sp bgt 2f # if > 0 - already on istack 1: mr sp,r3 # switch to istack 2: stwu r14,-4(sp) # save old SP on stack #endif subi sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame li r0,0 # R0 = 0 stw r0,0(sp) # backchain = 0 stw r0,8(sp) # return pc = 0 stwu sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame # where C code can save LR #if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR) lwi r3,0x0301 # r3 = type = INTR,RAISE lwz r4,CYGARC_PPCREG_VECTOR(r14) # arg1 = vector address srwi r4,r4,8 # arg1 = vector number xor r5,r5,r5 # arg2 = 0 bl cyg_instrument # call instrument function #endif hal_intc_decode r15,r14 # get table index #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \ || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT) # If we are supporting Ctrl-C interrupts from GDB, we must squirrel # away a pointer to the save interrupt state here so that we can # plant a breakpoint at some later time. .extern hal_saved_interrupt_state lwi r3,hal_saved_interrupt_state stw r14,0(r3) #endif #ifdef CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING #ifdef CYGPKG_HAL_POWERPC_MPC8xx # The CPM controller allows nested interrupts. However, # it sits on the back of the SIU controller which has no # HW support for this. In effect, SW masking of lower # priority IRQs in the SIU would be required for this to work. #endif #endif lwz r3,CYGARC_PPCREG_VECTOR(r14) # retrieve decoded vector # lwi r6,hal_interrupt_handlers # get interrupt handler table lwzx r6,r6,r15 # load routine pointer lwi r4,hal_interrupt_data # get interrupt data table lwzx r4,r4,r15 # load data pointer # R4 = data argument mr r5,r14 # R5 = saved registers mtctr r6 # put isr address in ctr bctrl # branch to ctr reg and link #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK # If we are returning from the last nested interrupt, move back # to the thread stack. interrupt_end() must be called on the # thread stack since it potentially causes a context switch. # Since we have arranged for the top of stack location to # contain the sp we need to go back to here, just pop it off # and put it in SP. lwz sp,CYGARC_PPC_STACK_FRAME_SIZE*2(sp) # sp = *sp subi sp,sp,CYGARC_PPC_STACK_FRAME_SIZE # make a null frame li r0,0 # R0 = 0 stw r0,0(sp) # backchain = 0 stw r0,8(sp) # return pc = 0 stwu sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) # create new stack frame # where C code can save LR #endif # On return r3 bit 1 will indicate whether a DSR is # to be posted. Pass this together with a pointer to # the interrupt object we have just used to the # interrupt tidy up routine. # Note that r14 and r15 are defined to be preserved across # calls by the calling convention, so they still contain # the register dump and the vector number respectively. lwi r4,hal_interrupt_objects # get interrupt object table lwzx r4,r4,r15 # load object pointer mr r5,r14 # arg3 = saved register dump .extern interrupt_end bl interrupt_end # call into C to finish off restore_state: # All done, restore CPU state and continue # retrieve CPU state pointer addi sp,sp,CYGARC_PPC_STACK_FRAME_SIZE*2 # Restore FPU registers hal_fpu_load sp # Restore variant registers hal_variant_load sp # get sprs we want to restore # stuff some of them into the CPU lwz r3,CYGARC_PPCREG_XER(sp) lwz r4,CYGARC_PPCREG_LR(sp) lwz r5,CYGARC_PPCREG_CTR(sp) mtxer r3 mtlr r4 mtctr r5 # Restore registers used in vsr (r14+r15) lwz r14,CYGARC_PPCREG_REGS+14*4(r1) lwz r15,CYGARC_PPCREG_REGS+15*4(r1) # restore registers r6..r12/r31 .set _reg,6 .rept MAX_SAVE_REG+1-6 lwz _reg,(CYGARC_PPCREG_REGS+_reg*4)(sp) .set _reg,_reg+1 .endr hal_cpu_int_disable # restore R0 and R2 lwz r0,CYGARC_PPCREG_REGS+0*4(sp) lwz r2,CYGARC_PPCREG_REGS+2*4(sp) # Here all the registers are loaded except # sp = HAL_SavedRegisters # r3 = ccr # r4 = srr0 = pc # r5 = srr1 = msr # # We have to disable interrupts while srr0 and # srr1 are loaded, since another interrupt will # destroy them. lwz r3,CYGARC_PPCREG_CR(sp) lwz r4,CYGARC_PPCREG_PC(sp) lwz r5,CYGARC_PPCREG_MSR(sp) mtcr r3 # set ccr mtsrr0 r4 # load old pc mtsrr1 r5 # load old msr #ifdef CYGDBG_HAL_POWERPC_FRAME_WALLS # Mark this frame as (almost) dead. lwi r3,0xDDDDDDD0 stw r3,CYGARC_PPCREG_WALL_HEAD(sp) lwi r3,0xDDDDDDD1 stw r3,CYGARC_PPCREG_WALL_TAIL(sp) #endif lwz r3,CYGARC_PPCREG_REGS+3*4(sp) # load r3 value lwz r4,CYGARC_PPCREG_REGS+4*4(sp) # load r4 value lwz r5,CYGARC_PPCREG_REGS+5*4(sp) # load r5 value lwz sp,CYGARC_PPCREG_REGS+1*4(sp) # restore sp sync # settle things down isync rfi # and return #if defined(CYGHWR_HAL_POWERPC_BOOK_E) ##--------------------------------------------------------------------------- ## Critical interrupt handling code. ## ## Book E processors save the old PC and MSR in CSRR0/1 for certain ## exceptions. This VSR saves the values from these registers before ## branching to the common VSR code. .globl cyg_hal_default_interrupt_vsr cyg_hal_default_critical_interrupt_vsr: # We come here with all register containing their # pre-exception values except: # R3 = ls 16 bits of vector address # R4 = saved CR # R5 = saved LR # LR = VSR address # SPRG1 = old R3 # SPRG2 = old R4 # SPRG3 = old R5 # CSRR0 = old PC # CSRR1 = old MSR subi sp,sp,CYGARC_PPC_EXCEPTION_DECREMENT # leave space for registers and # a safety margin stw r3,CYGARC_PPCREG_VECTOR(sp) # stash vector stw r4,CYGARC_PPCREG_CR(sp) # stash CR stw r5,CYGARC_PPCREG_LR(sp) # stash LR # Save exception PC and MSR mfspr r3,58 # Get CSSR0 stw r3,CYGARC_PPCREG_PC(sp) mfspr r3,59 # Get CSSR1 stw r3,CYGARC_PPCREG_MSR(sp) b cyg_hal_default_interrupt_vsr_common #endif ##----------------------------------------------------------------------------- ## Execute pending DSRs on the interrupt stack with interrupts enabled. ## Note: this can only be called from code running on a thread stack #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK .extern cyg_interrupt_call_pending_DSRs FUNC_START(hal_interrupt_stack_call_pending_DSRs) # Change to interrupt stack, save state and set up stack for # calls to C code. mr r3,sp lwi r4,__interrupt_stack subi r4,r4,24 # make space on stack mr sp,r4 stw r3,12(sp) # save old sp mfmsr r3 stw r3,16(sp) # save old MSR mflr r3 stw r3,20(sp) # save old LR li r0,0 stw r0,0(sp) # clear back chain stw r0,8(sp) # zero return pc hal_cpu_int_enable # Call into kernel which will execute DSRs stwu sp,-CYGARC_PPC_STACK_FRAME_SIZE(sp) bl cyg_interrupt_call_pending_DSRs addi sp,sp,CYGARC_PPC_STACK_FRAME_SIZE lwz r3,20(sp) # restore LR mtlr r3 lwz r5,12(sp) # get SP from saved state lwz r3,16(sp) # restore interrupt setting hal_cpu_int_merge r3,r4 mr sp,r5 # restore stack pointer blr # and return to caller #endif #--------------------------------------------------------------------------- ## Temporary interrupt stack .section ".bss" .balign 16 .global cyg_interrupt_stack_base cyg_interrupt_stack_base: __interrupt_stack_base: .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE .byte 0 .endr .balign 16 .global cyg_interrupt_stack cyg_interrupt_stack: __interrupt_stack: .long 0,0,0,0,0,0,0,0 #--------------------------------------------------------------------------- # end of vectors.S