diff options
Diffstat (limited to 'arch/sparc64/kernel/traps.c')
-rw-r--r-- | arch/sparc64/kernel/traps.c | 172 |
1 files changed, 100 insertions, 72 deletions
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 845809709..29032a901 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,8 +1,8 @@ -/* $Id: traps.c,v 1.64 1999/12/19 23:53:13 davem Exp $ +/* $Id: traps.c,v 1.65 2000/01/21 11:39:01 jj Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997,1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1999,2000 Jakub Jelinek (jakub@redhat.com) */ /* @@ -253,6 +253,8 @@ void rtrap_check(struct pt_regs *regs) void bad_trap (struct pt_regs *regs, long lvl) { + siginfo_t info; + lock_kernel (); if (lvl < 0x100) { char buffer[24]; @@ -262,9 +264,12 @@ void bad_trap (struct pt_regs *regs, long lvl) } if (regs->tstate & TSTATE_PRIV) die_if_kernel ("Kernel bad trap", regs); - current->thread.sig_desc = SUBSIG_BADTRAP(lvl - 0x100); - current->thread.sig_address = regs->tpc; - force_sig(SIGILL, current); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLTRP; + info.si_addr = (void *)regs->tpc; + info.si_trapno = lvl - 0x100; + force_sig_info(SIGILL, &info, current); unlock_kernel (); } @@ -281,6 +286,8 @@ void bad_trap_tl1 (struct pt_regs *regs, long lvl) void instruction_access_exception (struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { + siginfo_t info; + lock_kernel(); if (regs->tstate & TSTATE_PRIV) { #if 1 @@ -289,15 +296,20 @@ void instruction_access_exception (struct pt_regs *regs, #endif die_if_kernel("Iax", regs); } - current->thread.sig_desc = SUBSIG_ILLINST; - current->thread.sig_address = regs->tpc; - force_sig(SIGILL, current); + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_MAPERR; + info.si_addr = (void *)regs->tpc; + info.si_trapno = 0; + force_sig_info(SIGSEGV, &info, current); unlock_kernel(); } void data_access_exception (struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { + siginfo_t info; + if (regs->tstate & TSTATE_PRIV) { /* Test if this comes from uaccess places. */ unsigned long fixup, g2; @@ -326,8 +338,13 @@ void data_access_exception (struct pt_regs *regs, else rtrap_check(regs); #endif + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_MAPERR; + info.si_addr = (void *)sfar; + info.si_trapno = 0; lock_kernel(); - force_sig(SIGSEGV, current); + force_sig_info(SIGSEGV, &info, current); unlock_kernel(); } @@ -361,6 +378,22 @@ static __inline__ void clean_and_reenable_l1_caches(void) : "memory"); } +void do_iae(struct pt_regs *regs) +{ + siginfo_t info; + + clean_and_reenable_l1_caches(); + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_OBJERR; + info.si_addr = (void *)0; + info.si_trapno = 0; + lock_kernel(); + force_sig_info(SIGBUS, &info, current); + unlock_kernel(); +} + void do_dae(struct pt_regs *regs) { #ifdef CONFIG_PCI @@ -381,19 +414,7 @@ void do_dae(struct pt_regs *regs) return; } #endif - clean_and_reenable_l1_caches(); - lock_kernel(); - force_sig(SIGSEGV, current); - unlock_kernel(); -} - -void do_iae(struct pt_regs *regs) -{ - clean_and_reenable_l1_caches(); - - lock_kernel(); - force_sig(SIGSEGV, current); - unlock_kernel(); + do_iae(regs); } static char ecc_syndrome_table[] = { @@ -521,22 +542,26 @@ void do_fpe_common(struct pt_regs *regs) regs->tnpc += 4; } else { unsigned long fsr = current->thread.xfsr[0]; + siginfo_t info; - current->thread.sig_address = regs->tpc; - current->thread.sig_desc = SUBSIG_FPERROR; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_addr = (void *)regs->tpc; + info.si_trapno = 0; + info.si_code = __SI_FAULT; if ((fsr & 0x1c000) == (1 << 14)) { - if (fsr & 0x01) - current->thread.sig_desc = SUBSIG_FPINEXACT; - else if (fsr & 0x02) - current->thread.sig_desc = SUBSIG_FPDIVZERO; - else if (fsr & 0x04) - current->thread.sig_desc = SUBSIG_FPUNFLOW; + if (fsr & 0x10) + info.si_code = FPE_FLTINV; else if (fsr & 0x08) - current->thread.sig_desc = SUBSIG_FPOVFLOW; - else if (fsr & 0x10) - current->thread.sig_desc = SUBSIG_FPINTOVFL; + info.si_code = FPE_FLTOVF; + else if (fsr & 0x04) + info.si_code = FPE_FLTUND; + else if (fsr & 0x02) + info.si_code = FPE_FLTDIV; + else if (fsr & 0x01) + info.si_code = FPE_FLTRES; } - send_sig(SIGFPE, current, 1); + send_sig_info(SIGFPE, &info, current); } } @@ -570,24 +595,34 @@ void do_fpother(struct pt_regs *regs) void do_tof(struct pt_regs *regs) { + siginfo_t info; + if(regs->tstate & TSTATE_PRIV) die_if_kernel("Penguin overflow trap from kernel mode", regs); - current->thread.sig_address = regs->tpc; - current->thread.sig_desc = SUBSIG_TAG; /* as good as any */ - send_sig(SIGEMT, current, 1); + info.si_signo = SIGEMT; + info.si_errno = 0; + info.si_code = EMT_TAGOVF; + info.si_addr = (void *)regs->tpc; + info.si_trapno = 0; + send_sig_info(SIGEMT, &info, current); } void do_div0(struct pt_regs *regs) { - current->thread.sig_address = regs->tpc; - current->thread.sig_desc = SUBSIG_IDIVZERO; - send_sig(SIGFPE, current, 1); + siginfo_t info; + + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = FPE_INTDIV; + info.si_addr = (void *)regs->tpc; + info.si_trapno = 0; + send_sig_info(SIGFPE, &info, current); } void instruction_dump (unsigned int *pc) { int i; - + if((((unsigned long) pc) & 3)) return; @@ -671,6 +706,7 @@ void do_illegal_instruction(struct pt_regs *regs) unsigned long pc = regs->tpc; unsigned long tstate = regs->tstate; u32 insn; + siginfo_t info; if(tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); @@ -685,56 +721,48 @@ void do_illegal_instruction(struct pt_regs *regs) return; } } - current->thread.sig_address = pc; - current->thread.sig_desc = SUBSIG_ILLINST; - send_sig(SIGILL, current, 1); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = (void *)pc; + info.si_trapno = 0; + send_sig_info(SIGILL, &info, current); } void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) { + siginfo_t info; + if(regs->tstate & TSTATE_PRIV) { extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr); return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr); - } else { - current->thread.sig_address = regs->tpc; - current->thread.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGBUS, current, 1); } + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRALN; + info.si_addr = (void *)sfar; + info.si_trapno = 0; + send_sig_info(SIGBUS, &info, current); } void do_privop(struct pt_regs *regs) { - current->thread.sig_address = regs->tpc; - current->thread.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGILL, current, 1); -} - -void do_privact(struct pt_regs *regs) -{ - current->thread.sig_address = regs->tpc; - current->thread.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGILL, current, 1); -} + siginfo_t info; -void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc, - unsigned long tstate) -{ - if(tstate & TSTATE_PRIV) - die_if_kernel("Penguin instruction from Penguin mode??!?!", regs); - current->thread.sig_address = pc; - current->thread.sig_desc = SUBSIG_PRIVINST; - send_sig(SIGILL, current, 1); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_PRVOPC; + info.si_addr = (void *)regs->tpc; + info.si_trapno = 0; + send_sig_info(SIGILL, &info, current); } -void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, - unsigned long npc, unsigned long psr) +void do_privact(struct pt_regs *regs) { - current->thread.sig_address = regs->tpc; - current->thread.sig_desc = SUBSIG_IDIVZERO; - send_sig(SIGFPE, current, 1); + do_privop(regs); } /* Trap level 1 stuff or other traps we should never see... */ |