vectors.s
来自「eCos操作系统源码」· S 代码 · 共 1,024 行 · 第 1/2 页
S
1,024 行
sgpr 31,sp # == RA .set at mfhi a0 mflo a1 shi a0,sp slo a1,sp # K1 contains original SP ssp k1,sp # store in reg dump mfc0 t1,status mfc0 t2,cachectrl mvafc0 t3,epc sw t1,mipsreg_sr(sp) sw t2,mipsreg_cachectrl(sp) sva t3,mipsreg_pc(sp) hal_fpu_save sp # The machine state is now all saved on the stack. # Load Global Pointer register. la gp,_gp #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT .extern cyg_scheduler_sched_lock la v0,cyg_scheduler_sched_lock lw a0,0(v0) addi a0,a0,1 sw a0,0(v0)#endif move s0,sp # save pointer to saved state#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK la a0,__interrupt_stack # a0 = stack top la a1,__interrupt_stack_base # a1 = stack base sub a3,sp,a1 # a3 = sp - base bltz a3,1f # not on istack if < 0 nop # delay slot sub t0,a0,sp # t0 = top - sp bgtz t0,8f # already on istack if > 0 nop # delay slot1: move sp,a0 # switch to istack8: addi sp,sp,-8 # space for old SP # (8 to keep dword alignment!) sw s0,0(sp) # save old SP on stack #endif subu sp,sp,mips_stack_frame_size # make a null frame # Need to set up back pointers etc. ??? # Decode external interrupt via interrupt controller hal_intc_decode s2 # Here, s2 contains the number of the interrupt being serviced, # we need to derive from that the vector number to call in the ISR # table. hal_intc_translate s2,s1 # Here s1 is the number of the vector to be called and s2 is # the number of the interrupt being serviced. hal_diag_intr_start #if defined(CYGPKG_KERNEL_INSTRUMENT) && defined(CYGDBG_KERNEL_INSTRUMENT_INTR) # Call cyg_instrument to record that this interrupt is being raised. li a0,0x0301 # a0 = type = INTR,RAISE move a1,s1 # a1 = vector number jal cyg_instrument # call instrument function move a2,s2 # a2 = interrupt number#endif#if defined(CYGDBG_HAL_MIPS_DEBUG_GDB_CTRLC_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 la v0,hal_saved_interrupt_state sw s0,0(v0) #endif sll s1,s1,2 # s1 = byte offset of vector hal_cpu_except_enable # reenable exceptions la t2,hal_interrupt_handlers # handler table add t2,t2,s1 # address of ISR ptr lw t2,0(t2) # ISR pointer la a1,hal_interrupt_data # data table add a1,a1,s1 # address of data ptr lw a1,0(a1) # Data pointer move a0,s2 # pass interrupt number move a2,s0 # pass saved interrupt state jalr t2 # call ISR via t2 nop # (delay slot)#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. lw sp,mips_stack_frame_size(sp) # sp = *sp subu sp,sp,mips_stack_frame_size # make a null frame #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 v0 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 s0, s1 and s2 are defined to be preserved across # calls by the calling convention, so they still contain # the register dump, the vector offset and the interrupt number # respectively. move s2,v0 la a1,hal_interrupt_objects # interrupt object table add a1,a1,s1 # address of object ptr lw a1,0(a1) # a1 = object ptr move a2,s0 # arg3 = saved register dump .extern interrupt_end jal interrupt_end # call into C to finish off move a0,v0 # put ISR result in arg0 move v0,s2 # return value from isr#endif restore_state:#if defined(CYGSEM_HAL_USE_ROM_MONITOR_CygMon) move k0,v0#endif # All done, restore CPU state and continue addi sp,sp,mips_stack_frame_size # retrieve CPU state ptr # Disable interrupts again while we restore state. hal_cpu_int_disable hal_diag_restore hal_fpu_load sp lw t0,mipsreg_cachectrl(sp) lhi t1,sp llo t2,sp mtc0 t0,cachectrl mthi t1 mtlo t2 # load GPRs .set noat# lgpr 0,sp lgpr 1,sp lgpr 2,sp lgpr 3,sp lgpr 4,sp lgpr 5,sp lgpr 6,sp lgpr 7,sp lgpr 8,sp lgpr 9,sp lgpr 10,sp lgpr 11,sp lgpr 12,sp lgpr 13,sp lgpr 14,sp lgpr 15,sp lgpr 16,sp lgpr 17,sp lgpr 18,sp lgpr 19,sp lgpr 20,sp lgpr 21,sp lgpr 22,sp lgpr 23,sp lgpr 24,sp lgpr 25,sp# lgpr 26,sp # == K0# lgpr 27,sp # == K1 lgpr 28,sp # == GP# lgpr 29,sp # == SP lgpr 30,sp # == FP lgpr 31,sp # == RA .set at#if defined(CYGSEM_HAL_USE_ROM_MONITOR_CygMon) # If we have a Cygmon that wants to listen to network interrupts, then # the return code from the earlier call to hal_default_isr() will # have been negative to indicate this. So we jump into Cygmon here # because Cygmon requires the processor state to be the same as when # the interrupt was taken, but with k0 as the exception number. bgez k0,1f nop # Check for new cygmon sw k0,(mipsreg_regs+26*4)(sp) # save k0 la k1,0x80000100 + 41*4 # New cygmon "magic" id lw k1,0(k1) lui k0,0x55aa ori k0,0x4321 bne k0,k1,1f # Need to let cygmon handle this la k1,0x80000100 + 39*4 # stub entry vector lw k0,(mipsreg_regs+26*4)(sp) # restore k0 lw k1,0(k1) lw sp,(mipsreg_regs+29*4)(sp) # restore SP sll k0,1 # clear bit 31. jr k1 srl k0,1 1:#endif lw k1,mipsreg_sr(sp) # K1 = saved SR#if 0 < CYGINT_HAL_MIPS_INTERRUPT_RETURN_KEEP_SR_IM # Keep the current settings of the IM[7:0] bits within the status # register. These may be used as interrupt masks, so if an ISR or # DSR masks interrupts they must be preserved. # If they are not used, then this does no harm. ori k0,zero,0xff00 nor k0,k0,k0 # 0xffff00ff and k1,k1,k0 # all interrupts disabled mfc0 k0,status # V0 = current SR nop nop andi k0,k0,0xff00 # preserve interrupt set or k1,k1,k0 # insert into "saved SR"#endif // 0 < CYGINT_HAL_MIPS_INTERRUPT_RETURN_KEEP_SR_IM lva k0,mipsreg_pc(sp) # K0 = return PC lsp sp,sp # load SP # Invoke CPU specific mechanism for returning from this # exception hal_cpu_eret k0,k1 FUNC_END(__default_interrupt_vsr) hal_intc_decode_data##-----------------------------------------------------------------------------## 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_DSRsFUNC_START(hal_interrupt_stack_call_pending_DSRs) mfc0 t0,status # get status register value la v0,__interrupt_stack # v0 = interrupt stack move v1,sp # v1 = original stack ptr move sp,v0 # sp = interrupt stack addi sp,sp,-32 # make a null frame sw v1,16(sp) # save old sp sw ra,20(sp) # save old ra sw t0,24(sp) # save old sr hal_cpu_int_enable jal cyg_interrupt_call_pending_DSRs # call back to kernel nop lw a0,24(sp) # get status reg hal_cpu_int_merge a0 # merge with current SR lw ra,20(sp) # restore ra lw sp,16(sp) # restore sp jr ra # go back nop # delay slot FUNC_END(hal_interrupt_stack_call_pending_DSRs) #endif ##-----------------------------------------------------------------------------## Short circuit in case any code tries to use "__gccmain()"FUNC_START(__gccmain) jr ra nopFUNC_END(__gccmain)##-----------------------------------------------------------------------------## Switch to a new stack.## This is used in RedBoot to allow code to execute in a different## stack context.FUNC_START(hal_program_new_stack) # Arguments are: # a0 = function to call # a1 = stack pointer to use move v1,sp # v1 = original stack ptr move sp,a1 # sp = new stack addi sp,sp,-32 # make a null frame sva v1,8(sp) # save old sp sva ra,16(sp) # save old ra jalr a0 # call function nop lva ra,16(sp) # restore ra lva sp,8(sp) # restore sp jr ra # go back nop # delay slot FUNC_END(hal_program_new_stack) ##-----------------------------------------------------------------------------## hal_zero_bss## Zero bss. Done in assembler to be optimal rather than using memset,## which would risk zeroing bss while using it. FUNC_START(hal_zero_bss)#ifdef CYGHWR_HAL_MIPS_64BIT#define STORE_OP sd#define BLOCK_SHIFT 6#else#define STORE_OP sw#define BLOCK_SHIFT 5#endif la a0,__bss_start # start of bss la a1,__bss_end # end of bss andi a2,a0,mips_regsize-1 # is bss aligned? bne a2,zero,1f # skip word copy nop # loop with 8 stores per loop subu a3,a1,a0 # get length srl a3,a3,BLOCK_SHIFT # get number of blocks sll a3,a3,BLOCK_SHIFT # get length of blocks addu a3,a0,a3 # get end addr of blocks2: STORE_OP zero,(mips_regsize*0)(a0) STORE_OP zero,(mips_regsize*1)(a0) STORE_OP zero,(mips_regsize*2)(a0) STORE_OP zero,(mips_regsize*3)(a0) STORE_OP zero,(mips_regsize*4)(a0) STORE_OP zero,(mips_regsize*5)(a0) STORE_OP zero,(mips_regsize*6)(a0) STORE_OP zero,(mips_regsize*7)(a0) addu a0,a0,mips_regsize*8 # next addr bne a3,a0,2b # to next store nop # If length is a multiple of block size then we # are done and need to skip the byte loop beq a1,a0,3f nop # finish 1 byte at a time1: sb zero,0(a0) # zero memory addiu a0,a0,1 # next addr bne a0,a1,1b # to next store nop3: jr ra nopFUNC_END(hal_zero_bss) ##-----------------------------------------------------------------------------## VSR springboard for break instruction exceptions## Both GCC and GDB use break instructions. GCC for division-by-zero## notification and GDB for program-flow breakpoints. This springboard## looks for the d-b-z kind and directs them to another vector so libc## can handle these without affecting the debugger. FUNC_START(__break_vsr_springboard) mvafc0 k0,epc mfc0 k1,cause bltzl k1,1f addi k0,k0,4 # delay slot (only executed if BD set)1: lw k1,0(k0) # get break instruction la k0,0x0007000d # break 0x7 used by GCC for d-b-z bne k0,k1,2f nop ori k0,$0,14*4 # CYGNUM_HAL_VECTOR_DIV_BY_ZERO la k1,hal_vsr_table # address of VSR table add k1,k1,k0 # offset of VSR entry lw k1,0(k1) # k1 = pointer to VSR jr k1 # go there nop # (delay slot)2: ori k0,$0,9*4 # CYGNUM_HAL_VECTOR_BREAKPOINT j __default_exception_vsr nop # (delay slot)FUNC_END(__break_vsr_springboard)##-----------------------------------------------------------------------------## Interrupt Stack.## Used during intialization and for executing ISRs. .bss .balign 16 .global cyg_interrupt_stack_basecyg_interrupt_stack_base:__interrupt_stack_base: .rept CYGNUM_HAL_COMMON_INTERRUPTS_STACK_SIZE .byte 0 .endr .balign 16 .global cyg_interrupt_stackcyg_interrupt_stack:__interrupt_stack: .long 0,0,0,0,0,0,0,0 ##-----------------------------------------------------------------------------## VSR table.## The main interrupt code indirects through here to find the VSR## to execute for each architecture defined interrupt.## This is only used for simulated targets, on real targets a fixed location VSR## table is now allocated at 0x80000100.#ifndef CYG_HAL_MIPS_VSR_TABLE_DEFINED ## .section ".vsr_table","a" .data .globl hal_vsr_tablehal_vsr_table: .long __default_interrupt_vsr .rept 63 .long __default_exception_vsr .endr#endif #------------------------------------------------------------------------------# Interrupt vector tables.# These tables contain the isr, data and object pointers used to deliver# interrupts to user code.# hal_interrupt_level contains the interrupt level set by # HAL_INTERRUPT_CONFIGURE().# This is a default set that provide support only for the 6 external# interrupts in the status/cause registers. Platforms or boards are expected# to define their own versions of these if they have their own interrupt mappings.#ifndef CYG_HAL_MIPS_ISR_TABLES_DEFINED .extern hal_default_isr .data .globl hal_interrupt_handlershal_interrupt_handlers: .long hal_default_isr .long hal_default_isr .long hal_default_isr .long hal_default_isr .long hal_default_isr .long hal_default_isr .globl hal_interrupt_datahal_interrupt_data: .rept 6 .long 0 .endr .globl hal_interrupt_objectshal_interrupt_objects: .rept 6 .long 0 .endr#endif ##-----------------------------------------------------------------------------## end of vectors.S
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?