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