📄 entry.s
字号:
/* $Id: entry.S,v 1.168 2001/01/01 01:46:15 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996-1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) */#include <linux/config.h>#include <linux/errno.h>#include <asm/head.h>#include <asm/asi.h>#include <asm/smp.h>#include <asm/kgdb.h>#include <asm/contregs.h>#include <asm/ptrace.h>#include <asm/psr.h>#include <asm/cprefix.h>#include <asm/vaddrs.h>#include <asm/memreg.h>#include <asm/page.h>#ifdef CONFIG_SUN4#include <asm/pgtsun4.h>#else#include <asm/pgtsun4c.h>#endif#include <asm/winmacro.h>#include <asm/signal.h>#include <asm/obio.h>#include <asm/mxcc.h>#include <asm/asmmacro.h>#define curptr g6#define NR_SYSCALLS 256 /* Each OS is different... *//* First, KGDB low level things. This is a rewrite * of the routines found in the sparc-stub.c asm() statement * from the gdb distribution. This is also dual-purpose * as a software trap for userlevel programs. */ .data .align 4in_trap_handler: .word 0 .text .align 4! This function is called when any SPARC trap (except window overflow or! underflow) occurs. It makes sure that the invalid register window is still! available before jumping into C code. It will also restore the world if you! return from handle_exception. .globl C_LABEL(trap_low)C_LABEL(trap_low): rd %wim, %l3 SAVE_ALL sethi %hi(in_trap_handler), %l4 ld [%lo(in_trap_handler) + %l4], %l5 inc %l5 st %l5, [%lo(in_trap_handler) + %l4] /* Make sure kgdb sees the same state we just saved. */ LOAD_PT_GLOBALS(sp) LOAD_PT_INS(sp) ld [%sp + REGWIN_SZ + PT_Y], %l4 ld [%sp + REGWIN_SZ + PT_WIM], %l3 ld [%sp + REGWIN_SZ + PT_PSR], %l0 ld [%sp + REGWIN_SZ + PT_PC], %l1 ld [%sp + REGWIN_SZ + PT_NPC], %l2 rd %tbr, %l5 /* Never changes... */ /* Make kgdb exception frame. */ sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals ! + hidden arg + arg spill ! + doubleword alignment ! + registers[72] local var SAVE_KGDB_GLOBALS(sp) SAVE_KGDB_INS(sp) SAVE_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2) /* We are increasing PIL, so two writes. */ or %l0, PSR_PIL, %l0 wr %l0, 0, %psr WRITE_PAUSE wr %l0, PSR_ET, %psr WRITE_PAUSE call C_LABEL(handle_exception) add %sp, REGWIN_SZ, %o0 ! Pass address of registers /* Load new kgdb register set. */ LOAD_KGDB_GLOBALS(sp) LOAD_KGDB_INS(sp) LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2) wr %l4, 0x0, %y sethi %hi(in_trap_handler), %l4 ld [%lo(in_trap_handler) + %l4], %l5 dec %l5 st %l5, [%lo(in_trap_handler) + %l4] add %sp,(16+1+6+1+72)*4,%sp ! Undo the kgdb trap frame. /* Now take what kgdb did and place it into the pt_regs * frame which SparcLinux RESTORE_ALL understands., */ STORE_PT_INS(sp) STORE_PT_GLOBALS(sp) STORE_PT_YREG(sp, g2) STORE_PT_PRIV(sp, l0, l1, l2) RESTORE_ALL#ifdef CONFIG_BLK_DEV_FD .text .align 4 .globl C_LABEL(floppy_hardint)C_LABEL(floppy_hardint): /* * This code cannot touch registers %l0 %l1 and %l2 * because SAVE_ALL depends on their values. It depends * on %l3 also, but we regenerate it before a call. * Other registers are: * %l3 -- base address of fdc registers * %l4 -- pdma_vaddr * %l5 -- scratch for ld/st address * %l6 -- pdma_size * %l7 -- scratch [floppy byte, ld/st address, aux. data] */ /* Do we have work to do? */ sethi %hi(C_LABEL(doing_pdma)), %l7 ld [%l7 + %lo(C_LABEL(doing_pdma))], %l7 cmp %l7, 0 be floppy_dosoftint nop /* Load fdc register base */ sethi %hi(C_LABEL(fdc_status)), %l3 ld [%l3 + %lo(C_LABEL(fdc_status))], %l3 /* Setup register addresses */ sethi %hi(C_LABEL(pdma_vaddr)), %l5 ! transfer buffer ld [%l5 + %lo(C_LABEL(pdma_vaddr))], %l4 sethi %hi(C_LABEL(pdma_size)), %l5 ! bytes to go ld [%l5 + %lo(C_LABEL(pdma_size))], %l6next_byte: ldub [%l3], %l7 andcc %l7, 0x80, %g0 ! Does fifo still have data bz floppy_fifo_emptied ! fifo has been emptied... andcc %l7, 0x20, %g0 ! in non-dma mode still? bz floppy_overrun ! nope, overrun andcc %l7, 0x40, %g0 ! 0=write 1=read bz floppy_write sub %l6, 0x1, %l6 /* Ok, actually read this byte */ ldub [%l3 + 1], %l7 orcc %g0, %l6, %g0 stb %l7, [%l4] bne next_byte add %l4, 0x1, %l4 b floppy_tdone nopfloppy_write: /* Ok, actually write this byte */ ldub [%l4], %l7 orcc %g0, %l6, %g0 stb %l7, [%l3 + 1] bne next_byte add %l4, 0x1, %l4 /* fall through... */floppy_tdone: sethi %hi(C_LABEL(pdma_vaddr)), %l5 st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] sethi %hi(C_LABEL(pdma_size)), %l5 st %l6, [%l5 + %lo(C_LABEL(pdma_size))] /* Flip terminal count pin */ set C_LABEL(auxio_register), %l7 ld [%l7], %l7 set C_LABEL(sparc_cpu_model), %l5 ld [%l5], %l5 subcc %l5, 1, %g0 /* enum { sun4c = 1 }; */ be 1f ldub [%l7], %l5 or %l5, 0xc2, %l5 stb %l5, [%l7] andn %l5, 0x02, %l5 b 2f nop1: or %l5, 0xf4, %l5 stb %l5, [%l7] andn %l5, 0x04, %l52: /* Kill some time so the bits set */ WRITE_PAUSE WRITE_PAUSE stb %l5, [%l7] /* Prevent recursion */ sethi %hi(C_LABEL(doing_pdma)), %l7 b floppy_dosoftint st %g0, [%l7 + %lo(C_LABEL(doing_pdma))] /* We emptied the FIFO, but we haven't read everything * as of yet. Store the current transfer address and * bytes left to read so we can continue when the next * fast IRQ comes in. */floppy_fifo_emptied: sethi %hi(C_LABEL(pdma_vaddr)), %l5 st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] sethi %hi(C_LABEL(pdma_size)), %l7 st %l6, [%l7 + %lo(C_LABEL(pdma_size))] /* Restore condition codes */ wr %l0, 0x0, %psr WRITE_PAUSE jmp %l1 rett %l2floppy_overrun: sethi %hi(C_LABEL(pdma_vaddr)), %l5 st %l4, [%l5 + %lo(C_LABEL(pdma_vaddr))] sethi %hi(C_LABEL(pdma_size)), %l5 st %l6, [%l5 + %lo(C_LABEL(pdma_size))] /* Prevent recursion */ sethi %hi(C_LABEL(doing_pdma)), %l7 st %g0, [%l7 + %lo(C_LABEL(doing_pdma))] /* fall through... */floppy_dosoftint: rd %wim, %l3 SAVE_ALL /* Set all IRQs off. */ or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE mov 11, %o0 ! floppy irq level (unused anyway) mov %g0, %o1 ! devid is not used in fast interrupts call C_LABEL(sparc_floppy_irq) add %sp, REGWIN_SZ, %o2 ! struct pt_regs *regs RESTORE_ALL #endif /* (CONFIG_BLK_DEV_FD) */ /* Bad trap handler */ .globl bad_trap_handlerbad_trap_handler: SAVE_ALL wr %l0, PSR_ET, %psr WRITE_PAUSE mov %l7, %o0 ! trap number mov %l0, %o1 ! psr call C_LABEL(do_hw_interrupt) mov %l1, %o2 ! pc RESTORE_ALL /* For now all IRQ's not registered get sent here. handler_irq() will * see if a routine is registered to handle this interrupt and if not * it will say so on the console. */ .align 4 .globl real_irq_entry, patch_handler_irqreal_irq_entry: SAVE_ALL#ifdef CONFIG_SMP .globl patchme_maybe_smp_msg cmp %l7, 12patchme_maybe_smp_msg: bgu maybe_smp4m_msg nop#endifreal_irq_continue: or %l0, PSR_PIL, %g2 wr %g2, 0x0, %psr WRITE_PAUSE wr %g2, PSR_ET, %psr WRITE_PAUSE mov %l7, %o0 ! irq levelpatch_handler_irq: call C_LABEL(handler_irq) add %sp, REGWIN_SZ, %o1 ! pt_regs ptr or %l0, PSR_PIL, %g2 ! restore PIL after handler_irq wr %g2, PSR_ET, %psr ! keep ET up WRITE_PAUSE RESTORE_ALL#ifdef CONFIG_SMP /* SMP per-cpu ticker interrupts are handled specially. */smp4m_ticker: bne real_irq_continue+4 or %l0, PSR_PIL, %g2 wr %g2, 0x0, %psr WRITE_PAUSE wr %g2, PSR_ET, %psr WRITE_PAUSE call C_LABEL(smp4m_percpu_timer_interrupt) add %sp, REGWIN_SZ, %o0 wr %l0, PSR_ET, %psr WRITE_PAUSE RESTORE_ALL /* Here is where we check for possible SMP IPI passed to us * on some level other than 15 which is the NMI and only used * for cross calls. That has a separate entry point below. */maybe_smp4m_msg: GET_PROCESSOR_MID(o3, o2) set C_LABEL(sun4m_interrupts), %l5 ld [%l5], %o5 sethi %hi(0x60000000), %o4 sll %o3, 12, %o3 ld [%o5 + %o3], %o1 andcc %o1, %o4, %g0 be,a smp4m_ticker cmp %l7, 14 cmp %l7, 13 add %o5, %o3, %o5 bne,a 1f sethi %hi(0x40000000), %o2 sethi %hi(0x20000000), %o21: st %o2, [%o5 + 0x4] WRITE_PAUSE ld [%o5], %g0 WRITE_PAUSE or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE cmp %l7, 13 bne 2f nop call C_LABEL(smp_reschedule_irq) add %o7, 8, %o72: call C_LABEL(smp_stop_cpu_irq) nop RESTORE_ALL .align 4 .globl linux_trap_ipi15_sun4mlinux_trap_ipi15_sun4m: SAVE_ALL sethi %hi(0x80000000), %o2 GET_PROCESSOR_MID(o0, o1) set C_LABEL(sun4m_interrupts), %l5 ld [%l5], %o5 sll %o0, 12, %o0 add %o5, %o0, %o5 ld [%o5], %o3 andcc %o3, %o2, %g0 be 1f ! Must be an NMI async memory error st %o2, [%o5 + 4] WRITE_PAUSE ld [%o5], %g0 WRITE_PAUSE or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE call C_LABEL(smp4m_cross_call_irq) nop b ret_trap_lockless_ipi clr %l61: /* NMI async memory error handling. */ sethi %hi(0x80000000), %l4 sethi %hi(0x4000), %o3 sub %o5, %o0, %o5 add %o5, %o3, %l5 st %l4, [%l5 + 0xc] WRITE_PAUSE ld [%l5], %g0 WRITE_PAUSE or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE call C_LABEL(sun4m_nmi) nop st %l4, [%l5 + 0x8] WRITE_PAUSE ld [%l5], %g0 WRITE_PAUSE RESTORE_ALL .globl smp4d_ticker /* SMP per-cpu ticker interrupts are handled specially. */smp4d_ticker: SAVE_ALL or %l0, PSR_PIL, %g2 sethi %hi(CC_ICLR), %o0 sethi %hi(1 << 14), %o1 or %o0, %lo(CC_ICLR), %o0 stha %o1, [%o0] ASI_M_MXCC /* Clear PIL 14 in MXCC's ICLR */ wr %g2, 0x0, %psr WRITE_PAUSE wr %g2, PSR_ET, %psr WRITE_PAUSE call C_LABEL(smp4d_percpu_timer_interrupt) add %sp, REGWIN_SZ, %o0 wr %l0, PSR_ET, %psr WRITE_PAUSE RESTORE_ALL .align 4 .globl linux_trap_ipi15_sun4dlinux_trap_ipi15_sun4d: SAVE_ALL sethi %hi(CC_BASE), %o4 sethi %hi(MXCC_ERR_ME|MXCC_ERR_PEW|MXCC_ERR_ASE|MXCC_ERR_PEE), %o2 or %o4, (CC_EREG - CC_BASE), %o0 ldda [%o0] ASI_M_MXCC, %o0 andcc %o0, %o2, %g0 bne 1f sethi %hi(BB_STAT2), %o2 lduba [%o2] ASI_M_CTL, %o2 andcc %o2, BB_STAT2_MASK, %g0 bne 2f or %o4, (CC_ICLR - CC_BASE), %o0 sethi %hi(1 << 15), %o1 stha %o1, [%o0] ASI_M_MXCC /* Clear PIL 15 in MXCC's ICLR */ or %l0, PSR_PIL, %l4 wr %l4, 0x0, %psr WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE call C_LABEL(smp4d_cross_call_irq) nop b ret_trap_lockless_ipi clr %l61: /* MXCC error */2: /* BB error */ /* Disable PIL 15 */ set CC_IMSK, %l4 lduha [%l4] ASI_M_MXCC, %l5 sethi %hi(1 << 15), %l7 or %l5, %l7, %l5 stha %l5, [%l4] ASI_M_MXCC /* FIXME */1: b,a 1b#endif /* CONFIG_SMP */ /* This routine handles illegal instructions and privileged * instruction attempts from user code. */ .align 4 .globl bad_instructionbad_instruction: sethi %hi(0xc1f80000), %l4 ld [%l1], %l5 sethi %hi(0x81d80000), %l7 and %l5, %l4, %l5 cmp %l5, %l7 be 1f SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE add %sp, REGWIN_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(do_illegal_instruction) mov %l0, %o3 RESTORE_ALL1: /* unimplemented flush - just skip */ jmpl %l2, %g0 rett %l2 + 4 .align 4 .globl priv_instructionpriv_instruction: SAVE_ALL wr %l0, PSR_ET, %psr WRITE_PAUSE add %sp, REGWIN_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(do_priv_instruction) mov %l0, %o3 RESTORE_ALL /* This routine handles unaligned data accesses. */ .align 4 .globl mna_handlermna_handler: andcc %l0, PSR_PS, %g0 be mna_fromuser nop SAVE_ALL wr %l0, PSR_ET, %psr WRITE_PAUSE ld [%l1], %o1 call C_LABEL(kernel_unaligned_trap) add %sp, REGWIN_SZ, %o0 RESTORE_ALLmna_fromuser: SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE ld [%l1], %o1 call C_LABEL(user_unaligned_trap) add %sp, REGWIN_SZ, %o0 RESTORE_ALL /* This routine handles floating point disabled traps. */ .align 4 .globl fpd_trap_handlerfpd_trap_handler: SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE add %sp, REGWIN_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(do_fpd_trap) mov %l0, %o3 RESTORE_ALL /* This routine handles Floating Point Exceptions. */ .align 4 .globl fpe_trap_handlerfpe_trap_handler: set fpsave_magic, %l5 cmp %l1, %l5 be 1f sethi %hi(C_LABEL(fpsave)), %l5 or %l5, %lo(C_LABEL(fpsave)), %l5 cmp %l1, %l5 bne 2f sethi %hi(fpsave_catch2), %l5 or %l5, %lo(fpsave_catch2), %l5 wr %l0, 0x0, %psr WRITE_PAUSE jmp %l5 rett %l5 + 41: sethi %hi(fpsave_catch), %l5 or %l5, %lo(fpsave_catch), %l5 wr %l0, 0x0, %psr WRITE_PAUSE jmp %l5 rett %l5 + 42: SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE add %sp, REGWIN_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(do_fpe_trap) mov %l0, %o3 RESTORE_ALL /* This routine handles Tag Overflow Exceptions. */ .align 4 .globl do_tag_overflowdo_tag_overflow: SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE add %sp, REGWIN_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(handle_tag_overflow) mov %l0, %o3 RESTORE_ALL /* This routine handles Watchpoint Exceptions. */ .align 4 .globl do_watchpointdo_watchpoint: SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE add %sp, REGWIN_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call C_LABEL(handle_watchpoint) mov %l0, %o3 RESTORE_ALL /* This routine handles Register Access Exceptions. */ .align 4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -