Mercurial > ecos
diff 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 diff
new file mode 100644 --- /dev/null +++ b/packages/hal/powerpc/arch/current/src/vectors.S @@ -0,0 +1,798 @@ +##============================================================================= +## +## 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
