Mercurial > ecos
view packages/hal/powerpc/arch/current/src/vectors.S @ 0:3111d98ba7b3 ecos-v1_1-release
Initial commit of eCos version 1.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 11:16:07 +0000 |
| parents | |
| children | 443894e2e912 |
line wrap: on
line source
##============================================================================= ## ## vectors.S ## ## PowerPC exception vectors ## ##============================================================================= #####COPYRIGHTBEGIN#### # # ------------------------------------------- # The contents of this file are subject to the Cygnus eCos Public License # Version 1.0 (the "License"); you may not use this file except in # compliance with the License. You may obtain a copy of the License at # http://sourceware.cygnus.com/ecos # # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the # License for the specific language governing rights and limitations under # the License. # # The Original Code is eCos - Embedded Cygnus Operating System, released # September 30, 1998. # # The Initial Developer of the Original Code is Cygnus. Portions created # by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. # ------------------------------------------- # #####COPYRIGHTEND#### ##============================================================================= #######DESCRIPTIONBEGIN#### ## ## Author(s): nickg ## Contributors: nickg ## Date: 1997-10-16 ## 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#### ## ##============================================================================= #include <pkgconf/hal.h> #ifdef CYGPKG_KERNEL #include <pkgconf/kernel.h> // CYGPKG_KERNEL_INSTRUMENT #endif #include "cyg/hal/ppc.inc" #define FUNC_START(name) \ .type name,@function; \ .globl name; \ name: #============================================================================== .file "vectors.S" .extern hal_interrupt_handlers .extern hal_interrupt_data .extern hal_interrupt_objects .extern cyg_instrument .extern hal_hardware_init #============================================================================== # MSR initialization value # zero all bits except: # FP = floating point available # ME = machine check enabled # IP = vectors at 0xFFFxxxxx (ROM startup only) # RI = recoverable interrupt #ifdef CYG_HAL_STARTUP_ROM #define CYG_MSR 0x00003042 #endif #ifdef CYG_HAL_STARTUP_RAM #define CYG_MSR 0x00003002 #endif #============================================================================== # 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. # Note: Save some extra convenience registers (13-15) #ifdef CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT #define MAX_SAVE_REG 15 #else #define MAX_SAVE_REG 31 #endif #============================================================================== # Start by defining the exceptions vectors that must be placed at # locations 0xFFF00000 and 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. In RAM loaded configurations, this code may # be placed at 0x00000000 during loading. .section ".vectors","ax" #------------------------------------------------------------------------------ # Unused first vector. rom_vectors: lwi r3,_start mtlr r3 blr .byte 0x11 .byte 0x22 .byte 0x33 .byte 0x44 #------------------------------------------------------------------------------ # Reset vector. .p2align 8 .globl reset_vector reset_vector: lwi r3,_start mtlr r3 blr #------------------------------------------------------------------------------ # Macro for generating an exception vector service routine .macro exception_vector name .p2align 8 .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@L # load low half of vector address srwi r5,r5,6 # shift right by 6 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@L # reload low half of vector address blr # go to common code .endm #------------------------------------------------------------------------------ # Define the exception vectors. # These are the architecture defined vectors that # are always present. 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 # There are some additional vectors defined # on various implementations. #ifdef CYG_HAL_POWERPC_MP860 # MP860 vectors exception_vector software_emu exception_vector instruction_tlb_miss exception_vector data_tlb_miss exception_vector instruction_tlb_error exception_vector data_tlb_error exception_vector reserved_01500 exception_vector reserved_01600 exception_vector reserved_01700 exception_vector reserved_01800 exception_vector reserved_01900 exception_vector reserved_01A00 exception_vector reserved_01B00 exception_vector data_breakpoint exception_vector instruction_breakpoint exception_vector peripheral_breakpoint exception_vector NMI_port rom_vectors_end: #endif #============================================================================== # Real startup code. We jump here from the various reset vectors to set up the # world. .text .globl _start _start: # Set up MSR lwi r3,CYG_MSR mtmsr r3 #if defined(CYG_HAL_POWERPC_MP860) && !defined(CYG_HAL_POWERPC_SIM) # Disable special 860 "development support" which suppresses # trace exceptions. The CPU seems to hang, not executing from # offset 0x1e00(?) as expected. li r3,0 mtspr der, r3 #endif # Set up global offset table lwi r2,_GLOBAL_OFFSET_TABLE_ # set up time base register to zero xor r3,r3,r3 mtspr 284,r3 xor r4,r4,r4 mtspr 285,r4 # set up stack lwi sp,__interrupt_stack mtspr sprg0,sp # save in sprg0 for later use # Call platform specific hardware initialization bl hal_hardware_init # optional: initialize BAT registers #ifdef 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 1: lwz r0,0(r3) # get word from ROM stw r0,0(r4) # store in RAM addi r3,r3,4 # increment by 1 word addi r4,r4,4 # increment by 1 word cmplw r4,r5 # compare blt 1b # loop if not yet done 2: #ifdef CYG_HAL_POWERPC_COPY_VECTORS # Copy RAM exception vectors from ROM to RAM lwi r3,rom_vectors # r3 = rom start lwi r4,0 # r4 = ram start lwi r5,rom_vectors_end # r5 = rom end cmplw r3,r5 # skip if no vectors beq 2f 1: lwz r0,0(r3) # get word from ROM stw r0,0(r4) # store in RAM addi r3,r3,4 # increment by 1 word addi r4,r4,4 # increment by 1 word cmplw r3,r5 # compare blt 1b # loop if not yet done 2: #endif #endif # clear BSS lwi r3,__bss_start # r3 = start lwi r4,_end # r4 = end li r0,0 # r0 = 0 cmplw r3,r4 # skip if no bss beq 2f 1: stw r0,0(r3) # store zero addi r3,r3,4 # increment by 1 word cmplw r3,r4 # compare blt 1b # loop if not yet done 2: # set up stack to call cyg_start 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,-ppc_stack_frame_size(sp) # create new stack frame # for the call to __eabi # and cyg_start #ifdef CYG_KERNEL_USE_INIT_PRIORITY .extern cyg_hal_invoke_constructors bl cyg_hal_invoke_constructors # call c++ constructors #endif #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS .extern set_debug_traps bl set_debug_traps #endif .extern cyg_start 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 .extern __default_exception_vsr __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 subi r1,r1,ppc_exception_decrement # leave space for registers and # a safety margin # First, save away some registers stw r3,ppcreg_vector(r1) # stash vector stw r4,ppcreg_cr(r1) # stash CR stw r5,ppcreg_lr(r1) # stash LR mfspr r3,sprg1 # save original R3 stw r3,ppcreg_regs+3*4(r1) mfspr r4,sprg2 # save original R4 stw r4,ppcreg_regs+4*4(r1) mfspr r5,sprg3 # save original R5 stw r5,ppcreg_regs+5*4(r1) stw r0,ppcreg_regs(r1) # save R0 stw r2,ppcreg_regs+2*4(r1) # save R2 mr r3,r1 # recreate original R1 addi r3,r3,ppc_exception_decrement stw r3,ppcreg_regs+1*4(r1) # and save it in state # Save registers 6..31 .set _reg,6 .rept MAX_SAVE_REG+1-6 stw _reg,(ppcreg_regs+_reg*4)(r1) .set _reg,_reg+1 .endr # get remaining CPU registers mfxer r3 mfctr r5 mfdar r6 mfdsisr r7 mfpvr r8 mfsrr0 r9 mfsrr1 r10 # and store them stw r3,ppcreg_xer(r1) stw r5,ppcreg_ctr(r1) stw r6,ppcreg_dar(r1) stw r7,ppcreg_dsisr(r1) stw r8,ppcreg_pvr(r1) stw r9,ppcreg_pc(r1) stw r10,ppcreg_msr(r1) # 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,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,-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 exception_handler b exception_handler # call C code, r3 = registers # When the call returns it will go to restore_state below. #------------------------------------------------------------------------------ # Common interrupt handling code. .extern __default_interrupt_vsr __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 r1,r1,ppc_exception_decrement # leave space for registers and # a safety margin stw r3,ppcreg_vector(r1) # stash vector stw r4,ppcreg_cr(r1) # stash CR stw r5,ppcreg_lr(r1) # stash LR mfspr r3,sprg1 # save original R3 stw r3,ppcreg_regs+3*4(r1) mfspr r4,sprg2 # save original R4 stw r4,ppcreg_regs+4*4(r1) mfspr r5,sprg3 # save original R5 stw r5,ppcreg_regs+5*4(r1) stw r0,ppcreg_regs(r1) # save R0 stw r2,ppcreg_regs+2*4(r1) # save R2 mr r3,r1 # recreate original R1 addi r3,r3,ppc_exception_decrement stw r3,ppcreg_regs+1*4(r1) # and save it in state # Save registers 6..31 .set _reg,6 .rept MAX_SAVE_REG+1-6 stw _reg,(ppcreg_regs+_reg*4)(r1) .set _reg,_reg+1 .endr # get remaining CPU registers mfxer r3 mfctr r5 mfsrr0 r6 mfsrr1 r7 # and store them stw r3,ppcreg_xer(r1) stw r5,ppcreg_ctr(r1) stw r6,ppcreg_pc(r1) stw r7,ppcreg_msr(r1) # 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 _18Cyg_Scheduler_Base.sched_lock lwi r3,_18Cyg_Scheduler_Base.sched_lock lwz r4,0(r3) addi r4,r4,1 stw r4,0(r3) #endif mr r13,sp # R13 = 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 r13,-4(sp) # save old SP on stack #endif subi sp,sp,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,-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,ppcreg_vector(r13) # arg1 = vector address srwi r4,r4,8 # arg1 = vector number xor r5,r5,r5 # arg2 = 0 bl cyg_instrument # call instrument function #endif #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT .extern cyg_hal_gdb_isr lwz r3,ppcreg_vector(r13) # retrieve vector number cmpwi r3,0x0500 # if external, call HAL bne 1f # GDB ISR which will check bl cyg_hal_gdb_isr # for serial receive irq. cmpwi r3,0x0000 # Call ISR proper? beq 2f # (r3 is 0 when skipping # to avoid DSR call) 1: #endif lwz r3,ppcreg_vector(r13) # retrieve vector number srwi r15,r3,11 # isolate bit 11 of vector id slwi r15,r15,2 # convert to word offset srwi r3,r3,8 # R3 = vector no argument 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 mtctr r6 # put isr address in ctr bctrl # branch to ctr reg and link #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT # If interrupt was caused by GDB, the ISR call above # is skipped by jumping here. 2: #endif #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,ppc_stack_frame_size*2(sp) # sp = *sp subi sp,sp,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,-ppc_stack_frame_size(sp) # create new stack frame # where C code can save LR #endif #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT # We only need to call _interrupt_end() when there is a kernel # present to do any tidying up. # 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 r13 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 lwz r6,ppcreg_msr(r13) # restore msr, including mtmsr r6 # interrupt enable mr r5,r13 # arg3 = saved register dump .extern interrupt_end bl interrupt_end # call into C to finish off #endif restore_state: # All done, restore CPU state and continue addi sp,sp,ppc_stack_frame_size*2 # retrieve CPU state pointer # get sprs we want to restore lwz r3,ppcreg_cr(sp) lwz r4,ppcreg_pc(sp) lwz r5,ppcreg_msr(sp) lwz r6,ppcreg_xer(sp) lwz r7,ppcreg_lr(sp) lwz r8,ppcreg_ctr(sp) # stuff some of them into the CPU mtxer r6 mtlr r7 mtctr r8 # restore R0 and R2 lwz r0,ppcreg_regs(sp) lwz r2,ppcreg_regs+2*4(sp) # restore registers 6..31 .set _reg,6 .rept MAX_SAVE_REG+1-6 lwz _reg,(ppcreg_regs+_reg*4)(r1) .set _reg,_reg+1 .endr # Here all the registers are loaded except # r1 = ppcregs # 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. mtcr r3 # set ccr lwi r3,0x00003002 # do rest with ints disabled mtmsr r3 mtsrr0 r4 # load old pc mtsrr1 r5 # load old msr lwz r3,ppcreg_regs+3*4(r1) # load r3 value lwz r4,ppcreg_regs+4*4(r1) # load r4 value lwz r5,ppcreg_regs+5*4(r1) # load r5 value lwz r1,ppcreg_regs+1*4(r1) # restore r1 sync # settle things down isync rfi # and return #------------------------------------------------------------------------------ # This table contains a VSR pointer for each defined exception. # All of these except 5 and 9 point to the __default_exception_vsr # above, 5 and 9 point to the __default_interrupt_vsr. Entries in # this table may be changed using Cyg_Interrupt::set_vsr(). .data .globl hal_vsr_table hal_vsr_table: # Architecture defined vectors .long __default_exception_vsr # reserved .long __default_exception_vsr # system reset .long __default_exception_vsr # machine check .long __default_exception_vsr # data storage .long __default_exception_vsr # instruction storage .long __default_interrupt_vsr # external interrupt .long __default_exception_vsr # alignment .long __default_exception_vsr # program .long __default_exception_vsr # floating point unavailable .long __default_interrupt_vsr # decrementer .long __default_exception_vsr # reserved 0x0a00 .long __default_exception_vsr # reserved 0x0b00 .long __default_exception_vsr # system call .long __default_exception_vsr # trace .long __default_exception_vsr # floating point assist .long __default_exception_vsr # reserved 0x0f00 #ifdef CYG_HAL_POWERPC_MP860 # Implementation defined vectors .long __default_exception_vsr # software emulation .long __default_exception_vsr # instruction TLB miss .long __default_exception_vsr # data TLB miss .long __default_exception_vsr # instruction TLB error .long __default_exception_vsr # data TLB error .long __default_exception_vsr # reserved 0x1500 .long __default_exception_vsr # reserved 0x1600 .long __default_exception_vsr # reserved 0x1700 .long __default_exception_vsr # reserved 0x1800 .long __default_exception_vsr # reserved 0x1900 .long __default_exception_vsr # reserved 0x1a00 .long __default_exception_vsr # reserved 0x1b00 .long __default_exception_vsr # data breakpoint .long __default_exception_vsr # instruction breakpoint .long __default_exception_vsr # peripheral breakpoint .long __default_exception_vsr # non maskable development port #endif #------------------------------------------------------------------------------ # Interrupt vector tables. # These tables contain the isr, data and object pointers used to deliver # interrupts to user code. .data .extern hal_default_isr .globl hal_interrupt_handlers hal_interrupt_handlers: .rept 15 .long hal_default_isr .endr .globl hal_interrupt_data hal_interrupt_data: .rept 15 .long 0 .endr .globl hal_interrupt_objects hal_interrupt_objects: .rept 15 .long 0 .endr ##----------------------------------------------------------------------------- ## Temporary interrupt stack .section ".bss" .balign 16 __interrupt_stack_base: .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE .byte 0 .endr .balign 16 __interrupt_stack: .long 0,0,0,0,0,0,0,0 #------------------------------------------------------------------------------ #ifndef CYG_KERNEL_USE_INIT_PRIORITY # Head of __init function used for static constructors .section ".init.head","ax" .align 2 FUNC_START(__init) stwu 1,-8(1) mflr 0 stw 0,12(1) # Head of __fini function used for static destructors .section ".fini.head","ax" .align 2 FUNC_START(__fini) stwu 1,-8(1) mflr 0 stw 0,12(1) # Tail of __init used for static constructors .section ".init.tail","ax" lwz 0,12(1) mtlr 0 addi 1,1,8 blr # Tail of __fini used for static destructors .section ".fini.tail","ax" lwz 0,12(1) mtlr 0 addi 1,1,8 blr #endif #------------------------------------------------------------------------------ # end of vectors.S
