linux/arch/m68knommu/kernel/traps.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/m68knommu/kernel/traps.c
   3 *
   4 *  Copyright (C) 1993, 1994 by Hamish Macdonald
   5 *
   6 *  68040 fixes by Michael Rausch
   7 *  68040 fixes by Martin Apel
   8 *  68060 fixes by Roman Hodek
   9 *  68060 fixes by Jesper Skov
  10 *
  11 * This file is subject to the terms and conditions of the GNU General Public
  12 * License.  See the file COPYING in the main directory of this archive
  13 * for more details.
  14 */
  15
  16/*
  17 * Sets up all exception vectors
  18 */
  19#include <linux/sched.h>
  20#include <linux/signal.h>
  21#include <linux/kernel.h>
  22#include <linux/mm.h>
  23#include <linux/module.h>
  24#include <linux/types.h>
  25#include <linux/a.out.h>
  26#include <linux/user.h>
  27#include <linux/string.h>
  28#include <linux/linkage.h>
  29#include <linux/init.h>
  30#include <linux/ptrace.h>
  31#include <linux/kallsyms.h>
  32
  33#include <asm/setup.h>
  34#include <asm/fpu.h>
  35#include <asm/system.h>
  36#include <asm/uaccess.h>
  37#include <asm/traps.h>
  38#include <asm/pgtable.h>
  39#include <asm/machdep.h>
  40#include <asm/siginfo.h>
  41
  42static char const * const vec_names[] = {
  43        "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
  44        "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
  45        "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
  46        "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
  47        "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
  48        "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
  49        "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
  50        "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
  51        "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
  52        "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
  53        "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
  54        "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
  55        "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
  56        "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
  57        "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
  58        "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
  59        "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
  60        "FPCP UNSUPPORTED OPERATION",
  61        "MMU CONFIGURATION ERROR"
  62};
  63
  64void __init trap_init(void)
  65{
  66}
  67
  68void die_if_kernel(char *str, struct pt_regs *fp, int nr)
  69{
  70        if (!(fp->sr & PS_S))
  71                return;
  72
  73        console_verbose();
  74        printk(KERN_EMERG "%s: %08x\n",str,nr);
  75        printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x  SP: %p  a2: %08lx\n",
  76               fp->pc, fp->sr, fp, fp->a2);
  77        printk(KERN_EMERG "d0: %08lx    d1: %08lx    d2: %08lx    d3: %08lx\n",
  78               fp->d0, fp->d1, fp->d2, fp->d3);
  79        printk(KERN_EMERG "d4: %08lx    d5: %08lx    a0: %08lx    a1: %08lx\n",
  80               fp->d4, fp->d5, fp->a0, fp->a1);
  81
  82        printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
  83                current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
  84        show_stack(NULL, (unsigned long *)(fp + 1));
  85        add_taint(TAINT_DIE);
  86        do_exit(SIGSEGV);
  87}
  88
  89asmlinkage void buserr_c(struct frame *fp)
  90{
  91        /* Only set esp0 if coming from user mode */
  92        if (user_mode(&fp->ptregs))
  93                current->thread.esp0 = (unsigned long) fp;
  94
  95#if defined(DEBUG)
  96        printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
  97#endif
  98
  99        die_if_kernel("bad frame format",&fp->ptregs,0);
 100#if defined(DEBUG)
 101        printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
 102#endif
 103        force_sig(SIGSEGV, current);
 104}
 105
 106static void print_this_address(unsigned long addr, int i)
 107{
 108#ifdef CONFIG_KALLSYMS
 109        printk(KERN_EMERG " [%08lx] ", addr);
 110        print_symbol(KERN_CONT "%s\n", addr);
 111#else
 112        if (i % 5)
 113                printk(KERN_CONT " [%08lx] ", addr);
 114        else
 115                printk(KERN_CONT "\n" KERN_EMERG " [%08lx] ", addr);
 116        i++;
 117#endif
 118}
 119
 120int kstack_depth_to_print = 48;
 121
 122static void __show_stack(struct task_struct *task, unsigned long *stack)
 123{
 124        unsigned long *endstack, addr;
 125#ifdef CONFIG_FRAME_POINTER
 126        unsigned long *last_stack;
 127#endif
 128        int i;
 129
 130        if (!stack)
 131                stack = (unsigned long *)task->thread.ksp;
 132
 133        addr = (unsigned long) stack;
 134        endstack = (unsigned long *) PAGE_ALIGN(addr);
 135
 136        printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
 137        for (i = 0; i < kstack_depth_to_print; i++) {
 138                if (stack + 1 + i > endstack)
 139                        break;
 140                if (i % 8 == 0)
 141                        printk("\n" KERN_EMERG "       ");
 142                printk(" %08lx", *(stack + i));
 143        }
 144        printk("\n");
 145        i = 0;
 146
 147#ifdef CONFIG_FRAME_POINTER
 148        printk(KERN_EMERG "Call Trace:\n");
 149
 150        last_stack = stack - 1;
 151        while (stack <= endstack && stack > last_stack) {
 152
 153                addr = *(stack + 1);
 154                print_this_address(addr, i);
 155                i++;
 156
 157                last_stack = stack;
 158                stack = (unsigned long *)*stack;
 159        }
 160        printk("\n");
 161#else
 162        printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
 163        while (stack <= endstack) {
 164                addr = *stack++;
 165                /*
 166                 * If the address is either in the text segment of the kernel,
 167                 * or in a region which is occupied by a module then it *may*
 168                 * be the address of a calling routine; if so, print it so that
 169                 * someone tracing down the cause of the crash will be able to
 170                 * figure out the call path that was taken.
 171                 */
 172                if (__kernel_text_address(addr)) {
 173                        print_this_address(addr, i);
 174                        i++;
 175                }
 176        }
 177        printk(KERN_CONT "\n");
 178#endif
 179}
 180
 181void bad_super_trap(struct frame *fp)
 182{
 183        console_verbose();
 184        if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
 185                printk (KERN_WARNING "*** %s ***   FORMAT=%X\n",
 186                        vec_names[(fp->ptregs.vector) >> 2],
 187                        fp->ptregs.format);
 188        else
 189                printk (KERN_WARNING "*** Exception %d ***   FORMAT=%X\n",
 190                        (fp->ptregs.vector) >> 2, 
 191                        fp->ptregs.format);
 192        printk (KERN_WARNING "Current process id is %d\n", current->pid);
 193        die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
 194}
 195
 196asmlinkage void trap_c(struct frame *fp)
 197{
 198        int sig;
 199        siginfo_t info;
 200
 201        if (fp->ptregs.sr & PS_S) {
 202                if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
 203                        /* traced a trapping instruction */
 204                        current->ptrace |= PT_DTRACE;
 205                } else
 206                        bad_super_trap(fp);
 207                return;
 208        }
 209
 210        /* send the appropriate signal to the user program */
 211        switch ((fp->ptregs.vector) >> 2) {
 212            case VEC_ADDRERR:
 213                info.si_code = BUS_ADRALN;
 214                sig = SIGBUS;
 215                break;
 216            case VEC_ILLEGAL:
 217            case VEC_LINE10:
 218            case VEC_LINE11:
 219                info.si_code = ILL_ILLOPC;
 220                sig = SIGILL;
 221                break;
 222            case VEC_PRIV:
 223                info.si_code = ILL_PRVOPC;
 224                sig = SIGILL;
 225                break;
 226            case VEC_COPROC:
 227                info.si_code = ILL_COPROC;
 228                sig = SIGILL;
 229                break;
 230            case VEC_TRAP1: /* gdbserver breakpoint */
 231                fp->ptregs.pc -= 2;
 232                info.si_code = TRAP_TRACE;
 233                sig = SIGTRAP;
 234                break;
 235            case VEC_TRAP2:
 236            case VEC_TRAP3:
 237            case VEC_TRAP4:
 238            case VEC_TRAP5:
 239            case VEC_TRAP6:
 240            case VEC_TRAP7:
 241            case VEC_TRAP8:
 242            case VEC_TRAP9:
 243            case VEC_TRAP10:
 244            case VEC_TRAP11:
 245            case VEC_TRAP12:
 246            case VEC_TRAP13:
 247            case VEC_TRAP14:
 248                info.si_code = ILL_ILLTRP;
 249                sig = SIGILL;
 250                break;
 251            case VEC_FPBRUC:
 252            case VEC_FPOE:
 253            case VEC_FPNAN:
 254                info.si_code = FPE_FLTINV;
 255                sig = SIGFPE;
 256                break;
 257            case VEC_FPIR:
 258                info.si_code = FPE_FLTRES;
 259                sig = SIGFPE;
 260                break;
 261            case VEC_FPDIVZ:
 262                info.si_code = FPE_FLTDIV;
 263                sig = SIGFPE;
 264                break;
 265            case VEC_FPUNDER:
 266                info.si_code = FPE_FLTUND;
 267                sig = SIGFPE;
 268                break;
 269            case VEC_FPOVER:
 270                info.si_code = FPE_FLTOVF;
 271                sig = SIGFPE;
 272                break;
 273            case VEC_ZERODIV:
 274                info.si_code = FPE_INTDIV;
 275                sig = SIGFPE;
 276                break;
 277            case VEC_CHK:
 278            case VEC_TRAP:
 279                info.si_code = FPE_INTOVF;
 280                sig = SIGFPE;
 281                break;
 282            case VEC_TRACE:             /* ptrace single step */
 283                info.si_code = TRAP_TRACE;
 284                sig = SIGTRAP;
 285                break;
 286            case VEC_TRAP15:            /* breakpoint */
 287                info.si_code = TRAP_BRKPT;
 288                sig = SIGTRAP;
 289                break;
 290            default:
 291                info.si_code = ILL_ILLOPC;
 292                sig = SIGILL;
 293                break;
 294        }
 295        info.si_signo = sig;
 296        info.si_errno = 0;
 297        switch (fp->ptregs.format) {
 298            default:
 299                info.si_addr = (void *) fp->ptregs.pc;
 300                break;
 301            case 2:
 302                info.si_addr = (void *) fp->un.fmt2.iaddr;
 303                break;
 304            case 7:
 305                info.si_addr = (void *) fp->un.fmt7.effaddr;
 306                break;
 307            case 9:
 308                info.si_addr = (void *) fp->un.fmt9.iaddr;
 309                break;
 310            case 10:
 311                info.si_addr = (void *) fp->un.fmta.daddr;
 312                break;
 313            case 11:
 314                info.si_addr = (void *) fp->un.fmtb.daddr;
 315                break;
 316        }
 317        force_sig_info (sig, &info, current);
 318}
 319
 320asmlinkage void set_esp0(unsigned long ssp)
 321{
 322        current->thread.esp0 = ssp;
 323}
 324
 325/*
 326 * The architecture-independent backtrace generator
 327 */
 328void dump_stack(void)
 329{
 330        /*
 331         * We need frame pointers for this little trick, which works as follows:
 332         *
 333         * +------------+ 0x00
 334         * | Next SP    |       -> 0x0c
 335         * +------------+ 0x04
 336         * | Caller     |
 337         * +------------+ 0x08
 338         * | Local vars |       -> our stack var
 339         * +------------+ 0x0c
 340         * | Next SP    |       -> 0x18, that is what we pass to show_stack()
 341         * +------------+ 0x10
 342         * | Caller     |
 343         * +------------+ 0x14
 344         * | Local vars |
 345         * +------------+ 0x18
 346         * | ...        |
 347         * +------------+
 348         */
 349
 350        unsigned long *stack;
 351
 352        stack = (unsigned long *)&stack;
 353        stack++;
 354        __show_stack(current, stack);
 355}
 356EXPORT_SYMBOL(dump_stack);
 357
 358void show_stack(struct task_struct *task, unsigned long *stack)
 359{
 360        if (!stack && !task)
 361                dump_stack();
 362        else
 363                __show_stack(task, stack);
 364}
 365
 366#ifdef CONFIG_M68KFPU_EMU
 367asmlinkage void fpemu_signal(int signal, int code, void *addr)
 368{
 369        siginfo_t info;
 370
 371        info.si_signo = signal;
 372        info.si_errno = 0;
 373        info.si_code = code;
 374        info.si_addr = addr;
 375        force_sig_info(signal, &info, current);
 376}
 377#endif
 378