📄 entry.s
字号:
/* $Id: entry.S,v 1.170 2001/11/13 00:57:05 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/asm_offsets.h>#include <asm/psr.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/thread_info.h>#include <asm/param.h>#include <asm/asmmacro.h>#define curptr g6#define NR_SYSCALLS 283 /* Each OS is different... *//* These are just handy. */#define _SV save %sp, -STACKFRAME_SZ, %sp#define _RS restore #define FLUSH_ALL_KERNEL_WINDOWS \ _SV; _SV; _SV; _SV; _SV; _SV; _SV; \ _RS; _RS; _RS; _RS; _RS; _RS; _RS;/* 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#if 0 /* kgdb is dropped from 2.5.33 */! 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 trap_lowtrap_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 + STACKFRAME_SZ + PT_Y], %l4 ld [%sp + STACKFRAME_SZ + PT_WIM], %l3 ld [%sp + STACKFRAME_SZ + PT_PSR], %l0 ld [%sp + STACKFRAME_SZ + PT_PC], %l1 ld [%sp + STACKFRAME_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 handle_exception add %sp, STACKFRAME_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#endif#ifdef CONFIG_BLK_DEV_FD .text .align 4 .globl floppy_hardintfloppy_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(doing_pdma), %l7 ld [%l7 + %lo(doing_pdma)], %l7 cmp %l7, 0 be floppy_dosoftint nop /* Load fdc register base */ sethi %hi(fdc_status), %l3 ld [%l3 + %lo(fdc_status)], %l3 /* Setup register addresses */ sethi %hi(pdma_vaddr), %l5 ! transfer buffer ld [%l5 + %lo(pdma_vaddr)], %l4 sethi %hi(pdma_size), %l5 ! bytes to go ld [%l5 + %lo(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(pdma_vaddr), %l5 st %l4, [%l5 + %lo(pdma_vaddr)] sethi %hi(pdma_size), %l5 st %l6, [%l5 + %lo(pdma_size)] /* Flip terminal count pin */ set auxio_register, %l7 ld [%l7], %l7 set 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(doing_pdma), %l7 b floppy_dosoftint st %g0, [%l7 + %lo(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(pdma_vaddr), %l5 st %l4, [%l5 + %lo(pdma_vaddr)] sethi %hi(pdma_size), %l7 st %l6, [%l7 + %lo(pdma_size)] /* Restore condition codes */ wr %l0, 0x0, %psr WRITE_PAUSE jmp %l1 rett %l2floppy_overrun: sethi %hi(pdma_vaddr), %l5 st %l4, [%l5 + %lo(pdma_vaddr)] sethi %hi(pdma_size), %l5 st %l6, [%l5 + %lo(pdma_size)] /* Prevent recursion */ sethi %hi(doing_pdma), %l7 st %g0, [%l7 + %lo(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 sparc_floppy_irq add %sp, STACKFRAME_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 add %sp, STACKFRAME_SZ, %o0 ! pt_regs call do_hw_interrupt mov %l7, %o1 ! trap number 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 handler_irq add %sp, STACKFRAME_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 smp4m_percpu_timer_interrupt add %sp, STACKFRAME_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_PROCESSOR4M_ID(o3) set sun4m_interrupts, %l5 ld [%l5], %o5 sethi %hi(0x40000000), %o2 sll %o3, 12, %o3 ld [%o5 + %o3], %o1 andcc %o1, %o2, %g0 be,a smp4m_ticker cmp %l7, 14 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 call smp_reschedule_irq nop RESTORE_ALL .align 4 .globl linux_trap_ipi15_sun4mlinux_trap_ipi15_sun4m: SAVE_ALL sethi %hi(0x80000000), %o2 GET_PROCESSOR4M_ID(o0) set 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 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 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 smp4d_percpu_timer_interrupt add %sp, STACKFRAME_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 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, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call 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, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call 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 kernel_unaligned_trap add %sp, STACKFRAME_SZ, %o0 RESTORE_ALLmna_fromuser: SAVE_ALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE ld [%l1], %o1 call user_unaligned_trap add %sp, STACKFRAME_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, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call 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(fpsave), %l5 or %l5, %lo(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, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call 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, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call 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, STACKFRAME_SZ, %o0 mov %l1, %o1 mov %l2, %o2 call handle_watchpoint mov %l0, %o3 RESTORE_ALL /* This routine handles Register Access Exceptions. */ .align 4 .globl do_reg_accessdo_reg_access: SAVE_ALL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -