linux/arch/s390/kernel/traps.c
<<
>>
Prefs
   1/*
   2 *  arch/s390/kernel/traps.c
   3 *
   4 *  S390 version
   5 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
   6 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
   7 *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
   8 *
   9 *  Derived from "arch/i386/kernel/traps.c"
  10 *    Copyright (C) 1991, 1992 Linus Torvalds
  11 */
  12
  13/*
  14 * 'Traps.c' handles hardware traps and faults after we have saved some
  15 * state in 'asm.s'.
  16 */
  17#include <linux/sched.h>
  18#include <linux/kernel.h>
  19#include <linux/string.h>
  20#include <linux/errno.h>
  21#include <linux/ptrace.h>
  22#include <linux/timer.h>
  23#include <linux/mm.h>
  24#include <linux/smp.h>
  25#include <linux/init.h>
  26#include <linux/interrupt.h>
  27#include <linux/seq_file.h>
  28#include <linux/delay.h>
  29#include <linux/module.h>
  30#include <linux/kdebug.h>
  31#include <linux/kallsyms.h>
  32#include <linux/reboot.h>
  33#include <linux/kprobes.h>
  34#include <linux/bug.h>
  35#include <linux/utsname.h>
  36#include <asm/system.h>
  37#include <asm/uaccess.h>
  38#include <asm/io.h>
  39#include <asm/atomic.h>
  40#include <asm/mathemu.h>
  41#include <asm/cpcmd.h>
  42#include <asm/s390_ext.h>
  43#include <asm/lowcore.h>
  44#include <asm/debug.h>
  45#include "entry.h"
  46
  47pgm_check_handler_t *pgm_check_table[128];
  48
  49#ifdef CONFIG_SYSCTL
  50#ifdef CONFIG_PROCESS_DEBUG
  51int sysctl_userprocess_debug = 1;
  52#else
  53int sysctl_userprocess_debug = 0;
  54#endif
  55#endif
  56
  57extern pgm_check_handler_t do_protection_exception;
  58extern pgm_check_handler_t do_dat_exception;
  59extern pgm_check_handler_t do_asce_exception;
  60
  61#define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })
  62
  63#ifndef CONFIG_64BIT
  64#define FOURLONG "%08lx %08lx %08lx %08lx\n"
  65static int kstack_depth_to_print = 12;
  66#else /* CONFIG_64BIT */
  67#define FOURLONG "%016lx %016lx %016lx %016lx\n"
  68static int kstack_depth_to_print = 20;
  69#endif /* CONFIG_64BIT */
  70
  71/*
  72 * For show_trace we have tree different stack to consider:
  73 *   - the panic stack which is used if the kernel stack has overflown
  74 *   - the asynchronous interrupt stack (cpu related)
  75 *   - the synchronous kernel stack (process related)
  76 * The stack trace can start at any of the three stack and can potentially
  77 * touch all of them. The order is: panic stack, async stack, sync stack.
  78 */
  79static unsigned long
  80__show_trace(unsigned long sp, unsigned long low, unsigned long high)
  81{
  82        struct stack_frame *sf;
  83        struct pt_regs *regs;
  84
  85        while (1) {
  86                sp = sp & PSW_ADDR_INSN;
  87                if (sp < low || sp > high - sizeof(*sf))
  88                        return sp;
  89                sf = (struct stack_frame *) sp;
  90                printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
  91                print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
  92                /* Follow the backchain. */
  93                while (1) {
  94                        low = sp;
  95                        sp = sf->back_chain & PSW_ADDR_INSN;
  96                        if (!sp)
  97                                break;
  98                        if (sp <= low || sp > high - sizeof(*sf))
  99                                return sp;
 100                        sf = (struct stack_frame *) sp;
 101                        printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
 102                        print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
 103                }
 104                /* Zero backchain detected, check for interrupt frame. */
 105                sp = (unsigned long) (sf + 1);
 106                if (sp <= low || sp > high - sizeof(*regs))
 107                        return sp;
 108                regs = (struct pt_regs *) sp;
 109                printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
 110                print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
 111                low = sp;
 112                sp = regs->gprs[15];
 113        }
 114}
 115
 116static void show_trace(struct task_struct *task, unsigned long *stack)
 117{
 118        register unsigned long __r15 asm ("15");
 119        unsigned long sp;
 120
 121        sp = (unsigned long) stack;
 122        if (!sp)
 123                sp = task ? task->thread.ksp : __r15;
 124        printk("Call Trace:\n");
 125#ifdef CONFIG_CHECK_STACK
 126        sp = __show_trace(sp, S390_lowcore.panic_stack - 4096,
 127                          S390_lowcore.panic_stack);
 128#endif
 129        sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE,
 130                          S390_lowcore.async_stack);
 131        if (task)
 132                __show_trace(sp, (unsigned long) task_stack_page(task),
 133                             (unsigned long) task_stack_page(task) + THREAD_SIZE);
 134        else
 135                __show_trace(sp, S390_lowcore.thread_info,
 136                             S390_lowcore.thread_info + THREAD_SIZE);
 137        if (!task)
 138                task = current;
 139        debug_show_held_locks(task);
 140}
 141
 142void show_stack(struct task_struct *task, unsigned long *sp)
 143{
 144        register unsigned long * __r15 asm ("15");
 145        unsigned long *stack;
 146        int i;
 147
 148        if (!sp)
 149                stack = task ? (unsigned long *) task->thread.ksp : __r15;
 150        else
 151                stack = sp;
 152
 153        for (i = 0; i < kstack_depth_to_print; i++) {
 154                if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
 155                        break;
 156                if (i && ((i * sizeof (long) % 32) == 0))
 157                        printk("\n       ");
 158                printk("%p ", (void *)*stack++);
 159        }
 160        printk("\n");
 161        show_trace(task, sp);
 162}
 163
 164static void show_last_breaking_event(struct pt_regs *regs)
 165{
 166#ifdef CONFIG_64BIT
 167        printk("Last Breaking-Event-Address:\n");
 168        printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN);
 169        print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN);
 170#endif
 171}
 172
 173/*
 174 * The architecture-independent dump_stack generator
 175 */
 176void dump_stack(void)
 177{
 178        printk("CPU: %d %s %s %.*s\n",
 179               task_thread_info(current)->cpu, print_tainted(),
 180               init_utsname()->release,
 181               (int)strcspn(init_utsname()->version, " "),
 182               init_utsname()->version);
 183        printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
 184               current->comm, current->pid, current,
 185               (void *) current->thread.ksp);
 186        show_stack(NULL, NULL);
 187}
 188EXPORT_SYMBOL(dump_stack);
 189
 190static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
 191{
 192        return (regs->psw.mask & bits) / ((~bits + 1) & bits);
 193}
 194
 195void show_registers(struct pt_regs *regs)
 196{
 197        char *mode;
 198
 199        mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
 200        printk("%s PSW : %p %p",
 201               mode, (void *) regs->psw.mask,
 202               (void *) regs->psw.addr);
 203        print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
 204        printk("           R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
 205               "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
 206               mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
 207               mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
 208               mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
 209               mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
 210               mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
 211#ifdef CONFIG_64BIT
 212        printk(" EA:%x", mask_bits(regs, PSW_BASE_BITS));
 213#endif
 214        printk("\n%s GPRS: " FOURLONG, mode,
 215               regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
 216        printk("           " FOURLONG,
 217               regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
 218        printk("           " FOURLONG,
 219               regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
 220        printk("           " FOURLONG,
 221               regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
 222
 223        show_code(regs);
 224}       
 225
 226void show_regs(struct pt_regs *regs)
 227{
 228        print_modules();
 229        printk("CPU: %d %s %s %.*s\n",
 230               task_thread_info(current)->cpu, print_tainted(),
 231               init_utsname()->release,
 232               (int)strcspn(init_utsname()->version, " "),
 233               init_utsname()->version);
 234        printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
 235               current->comm, current->pid, current,
 236               (void *) current->thread.ksp);
 237        show_registers(regs);
 238        /* Show stack backtrace if pt_regs is from kernel mode */
 239        if (!(regs->psw.mask & PSW_MASK_PSTATE))
 240                show_trace(NULL, (unsigned long *) regs->gprs[15]);
 241        show_last_breaking_event(regs);
 242}
 243
 244/* This is called from fs/proc/array.c */
 245void task_show_regs(struct seq_file *m, struct task_struct *task)
 246{
 247        struct pt_regs *regs;
 248
 249        regs = task_pt_regs(task);
 250        seq_printf(m, "task: %p, ksp: %p\n",
 251                       task, (void *)task->thread.ksp);
 252        seq_printf(m, "User PSW : %p %p\n",
 253                       (void *) regs->psw.mask, (void *)regs->psw.addr);
 254
 255        seq_printf(m, "User GPRS: " FOURLONG,
 256                          regs->gprs[0], regs->gprs[1],
 257                          regs->gprs[2], regs->gprs[3]);
 258        seq_printf(m, "           " FOURLONG,
 259                          regs->gprs[4], regs->gprs[5],
 260                          regs->gprs[6], regs->gprs[7]);
 261        seq_printf(m, "           " FOURLONG,
 262                          regs->gprs[8], regs->gprs[9],
 263                          regs->gprs[10], regs->gprs[11]);
 264        seq_printf(m, "           " FOURLONG,
 265                          regs->gprs[12], regs->gprs[13],
 266                          regs->gprs[14], regs->gprs[15]);
 267        seq_printf(m, "User ACRS: %08x %08x %08x %08x\n",
 268                          task->thread.acrs[0], task->thread.acrs[1],
 269                          task->thread.acrs[2], task->thread.acrs[3]);
 270        seq_printf(m, "           %08x %08x %08x %08x\n",
 271                          task->thread.acrs[4], task->thread.acrs[5],
 272                          task->thread.acrs[6], task->thread.acrs[7]);
 273        seq_printf(m, "           %08x %08x %08x %08x\n",
 274                          task->thread.acrs[8], task->thread.acrs[9],
 275                          task->thread.acrs[10], task->thread.acrs[11]);
 276        seq_printf(m, "           %08x %08x %08x %08x\n",
 277                          task->thread.acrs[12], task->thread.acrs[13],
 278                          task->thread.acrs[14], task->thread.acrs[15]);
 279}
 280
 281static DEFINE_SPINLOCK(die_lock);
 282
 283void die(const char * str, struct pt_regs * regs, long err)
 284{
 285        static int die_counter;
 286
 287        oops_enter();
 288        debug_stop_all();
 289        console_verbose();
 290        spin_lock_irq(&die_lock);
 291        bust_spinlocks(1);
 292        printk("%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
 293#ifdef CONFIG_PREEMPT
 294        printk("PREEMPT ");
 295#endif
 296#ifdef CONFIG_SMP
 297        printk("SMP ");
 298#endif
 299#ifdef CONFIG_DEBUG_PAGEALLOC
 300        printk("DEBUG_PAGEALLOC");
 301#endif
 302        printk("\n");
 303        notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
 304        show_regs(regs);
 305        bust_spinlocks(0);
 306        add_taint(TAINT_DIE);
 307        spin_unlock_irq(&die_lock);
 308        if (in_interrupt())
 309                panic("Fatal exception in interrupt");
 310        if (panic_on_oops)
 311                panic("Fatal exception: panic_on_oops");
 312        oops_exit();
 313        do_exit(SIGSEGV);
 314}
 315
 316static void inline
 317report_user_fault(long interruption_code, struct pt_regs *regs)
 318{
 319#if defined(CONFIG_SYSCTL)
 320        if (!sysctl_userprocess_debug)
 321                return;
 322#endif
 323#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
 324        printk("User process fault: interruption code 0x%lX\n",
 325               interruption_code);
 326        show_regs(regs);
 327#endif
 328}
 329
 330int is_valid_bugaddr(unsigned long addr)
 331{
 332        return 1;
 333}
 334
 335static void __kprobes inline do_trap(long interruption_code, int signr,
 336                                        char *str, struct pt_regs *regs,
 337                                        siginfo_t *info)
 338{
 339        /*
 340         * We got all needed information from the lowcore and can
 341         * now safely switch on interrupts.
 342         */
 343        if (regs->psw.mask & PSW_MASK_PSTATE)
 344                local_irq_enable();
 345
 346        if (notify_die(DIE_TRAP, str, regs, interruption_code,
 347                                interruption_code, signr) == NOTIFY_STOP)
 348                return;
 349
 350        if (regs->psw.mask & PSW_MASK_PSTATE) {
 351                struct task_struct *tsk = current;
 352
 353                tsk->thread.trap_no = interruption_code & 0xffff;
 354                force_sig_info(signr, info, tsk);
 355                report_user_fault(interruption_code, regs);
 356        } else {
 357                const struct exception_table_entry *fixup;
 358                fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
 359                if (fixup)
 360                        regs->psw.addr = fixup->fixup | PSW_ADDR_AMODE;
 361                else {
 362                        enum bug_trap_type btt;
 363
 364                        btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
 365                        if (btt == BUG_TRAP_TYPE_WARN)
 366                                return;
 367                        die(str, regs, interruption_code);
 368                }
 369        }
 370}
 371
 372static inline void __user *get_check_address(struct pt_regs *regs)
 373{
 374        return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
 375}
 376
 377void __kprobes do_single_step(struct pt_regs *regs)
 378{
 379        if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0,
 380                                        SIGTRAP) == NOTIFY_STOP){
 381                return;
 382        }
 383        if ((current->ptrace & PT_PTRACED) != 0)
 384                force_sig(SIGTRAP, current);
 385}
 386
 387static void default_trap_handler(struct pt_regs * regs, long interruption_code)
 388{
 389        if (regs->psw.mask & PSW_MASK_PSTATE) {
 390                local_irq_enable();
 391                do_exit(SIGSEGV);
 392                report_user_fault(interruption_code, regs);
 393        } else
 394                die("Unknown program exception", regs, interruption_code);
 395}
 396
 397#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
 398static void name(struct pt_regs * regs, long interruption_code) \
 399{ \
 400        siginfo_t info; \
 401        info.si_signo = signr; \
 402        info.si_errno = 0; \
 403        info.si_code = sicode; \
 404        info.si_addr = siaddr; \
 405        do_trap(interruption_code, signr, str, regs, &info); \
 406}
 407
 408DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception,
 409              ILL_ILLADR, get_check_address(regs))
 410DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
 411              ILL_ILLOPN, get_check_address(regs))
 412DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
 413              FPE_INTDIV, get_check_address(regs))
 414DO_ERROR_INFO(SIGFPE,  "fixpoint overflow exception", overflow_exception,
 415              FPE_INTOVF, get_check_address(regs))
 416DO_ERROR_INFO(SIGFPE,  "HFP overflow exception", hfp_overflow_exception,
 417              FPE_FLTOVF, get_check_address(regs))
 418DO_ERROR_INFO(SIGFPE,  "HFP underflow exception", hfp_underflow_exception,
 419              FPE_FLTUND, get_check_address(regs))
 420DO_ERROR_INFO(SIGFPE,  "HFP significance exception", hfp_significance_exception,
 421              FPE_FLTRES, get_check_address(regs))
 422DO_ERROR_INFO(SIGFPE,  "HFP divide exception", hfp_divide_exception,
 423              FPE_FLTDIV, get_check_address(regs))
 424DO_ERROR_INFO(SIGFPE,  "HFP square root exception", hfp_sqrt_exception,
 425              FPE_FLTINV, get_check_address(regs))
 426DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
 427              ILL_ILLOPN, get_check_address(regs))
 428DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
 429              ILL_PRVOPC, get_check_address(regs))
 430DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
 431              ILL_ILLOPN, get_check_address(regs))
 432DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
 433              ILL_ILLOPN, get_check_address(regs))
 434
 435static inline void
 436do_fp_trap(struct pt_regs *regs, void __user *location,
 437           int fpc, long interruption_code)
 438{
 439        siginfo_t si;
 440
 441        si.si_signo = SIGFPE;
 442        si.si_errno = 0;
 443        si.si_addr = location;
 444        si.si_code = 0;
 445        /* FPC[2] is Data Exception Code */
 446        if ((fpc & 0x00000300) == 0) {
 447                /* bits 6 and 7 of DXC are 0 iff IEEE exception */
 448                if (fpc & 0x8000) /* invalid fp operation */
 449                        si.si_code = FPE_FLTINV;
 450                else if (fpc & 0x4000) /* div by 0 */
 451                        si.si_code = FPE_FLTDIV;
 452                else if (fpc & 0x2000) /* overflow */
 453                        si.si_code = FPE_FLTOVF;
 454                else if (fpc & 0x1000) /* underflow */
 455                        si.si_code = FPE_FLTUND;
 456                else if (fpc & 0x0800) /* inexact */
 457                        si.si_code = FPE_FLTRES;
 458        }
 459        current->thread.ieee_instruction_pointer = (addr_t) location;
 460        do_trap(interruption_code, SIGFPE,
 461                "floating point exception", regs, &si);
 462}
 463
 464static void illegal_op(struct pt_regs * regs, long interruption_code)
 465{
 466        siginfo_t info;
 467        __u8 opcode[6];
 468        __u16 __user *location;
 469        int signal = 0;
 470
 471        location = get_check_address(regs);
 472
 473        /*
 474         * We got all needed information from the lowcore and can
 475         * now safely switch on interrupts.
 476         */
 477        if (regs->psw.mask & PSW_MASK_PSTATE)
 478                local_irq_enable();
 479
 480        if (regs->psw.mask & PSW_MASK_PSTATE) {
 481                if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
 482                        return;
 483                if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
 484                        if (current->ptrace & PT_PTRACED)
 485                                force_sig(SIGTRAP, current);
 486                        else
 487                                signal = SIGILL;
 488#ifdef CONFIG_MATHEMU
 489                } else if (opcode[0] == 0xb3) {
 490                        if (get_user(*((__u16 *) (opcode+2)), location+1))
 491                                return;
 492                        signal = math_emu_b3(opcode, regs);
 493                } else if (opcode[0] == 0xed) {
 494                        if (get_user(*((__u32 *) (opcode+2)),
 495                                     (__u32 __user *)(location+1)))
 496                                return;
 497                        signal = math_emu_ed(opcode, regs);
 498                } else if (*((__u16 *) opcode) == 0xb299) {
 499                        if (get_user(*((__u16 *) (opcode+2)), location+1))
 500                                return;
 501                        signal = math_emu_srnm(opcode, regs);
 502                } else if (*((__u16 *) opcode) == 0xb29c) {
 503                        if (get_user(*((__u16 *) (opcode+2)), location+1))
 504                                return;
 505                        signal = math_emu_stfpc(opcode, regs);
 506                } else if (*((__u16 *) opcode) == 0xb29d) {
 507                        if (get_user(*((__u16 *) (opcode+2)), location+1))
 508                                return;
 509                        signal = math_emu_lfpc(opcode, regs);
 510#endif
 511                } else
 512                        signal = SIGILL;
 513        } else {
 514                /*
 515                 * If we get an illegal op in kernel mode, send it through the
 516                 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
 517                 */
 518                if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
 519                               3, SIGTRAP) != NOTIFY_STOP)
 520                        signal = SIGILL;
 521        }
 522
 523#ifdef CONFIG_MATHEMU
 524        if (signal == SIGFPE)
 525                do_fp_trap(regs, location,
 526                           current->thread.fp_regs.fpc, interruption_code);
 527        else if (signal == SIGSEGV) {
 528                info.si_signo = signal;
 529                info.si_errno = 0;
 530                info.si_code = SEGV_MAPERR;
 531                info.si_addr = (void __user *) location;
 532                do_trap(interruption_code, signal,
 533                        "user address fault", regs, &info);
 534        } else
 535#endif
 536        if (signal) {
 537                info.si_signo = signal;
 538                info.si_errno = 0;
 539                info.si_code = ILL_ILLOPC;
 540                info.si_addr = (void __user *) location;
 541                do_trap(interruption_code, signal,
 542                        "illegal operation", regs, &info);
 543        }
 544}
 545
 546
 547#ifdef CONFIG_MATHEMU
 548asmlinkage void 
 549specification_exception(struct pt_regs * regs, long interruption_code)
 550{
 551        __u8 opcode[6];
 552        __u16 __user *location = NULL;
 553        int signal = 0;
 554
 555        location = (__u16 __user *) get_check_address(regs);
 556
 557        /*
 558         * We got all needed information from the lowcore and can
 559         * now safely switch on interrupts.
 560         */
 561        if (regs->psw.mask & PSW_MASK_PSTATE)
 562                local_irq_enable();
 563
 564        if (regs->psw.mask & PSW_MASK_PSTATE) {
 565                get_user(*((__u16 *) opcode), location);
 566                switch (opcode[0]) {
 567                case 0x28: /* LDR Rx,Ry   */
 568                        signal = math_emu_ldr(opcode);
 569                        break;
 570                case 0x38: /* LER Rx,Ry   */
 571                        signal = math_emu_ler(opcode);
 572                        break;
 573                case 0x60: /* STD R,D(X,B) */
 574                        get_user(*((__u16 *) (opcode+2)), location+1);
 575                        signal = math_emu_std(opcode, regs);
 576                        break;
 577                case 0x68: /* LD R,D(X,B) */
 578                        get_user(*((__u16 *) (opcode+2)), location+1);
 579                        signal = math_emu_ld(opcode, regs);
 580                        break;
 581                case 0x70: /* STE R,D(X,B) */
 582                        get_user(*((__u16 *) (opcode+2)), location+1);
 583                        signal = math_emu_ste(opcode, regs);
 584                        break;
 585                case 0x78: /* LE R,D(X,B) */
 586                        get_user(*((__u16 *) (opcode+2)), location+1);
 587                        signal = math_emu_le(opcode, regs);
 588                        break;
 589                default:
 590                        signal = SIGILL;
 591                        break;
 592                }
 593        } else
 594                signal = SIGILL;
 595
 596        if (signal == SIGFPE)
 597                do_fp_trap(regs, location,
 598                           current->thread.fp_regs.fpc, interruption_code);
 599        else if (signal) {
 600                siginfo_t info;
 601                info.si_signo = signal;
 602                info.si_errno = 0;
 603                info.si_code = ILL_ILLOPN;
 604                info.si_addr = location;
 605                do_trap(interruption_code, signal, 
 606                        "specification exception", regs, &info);
 607        }
 608}
 609#else
 610DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
 611              ILL_ILLOPN, get_check_address(regs));
 612#endif
 613
 614static void data_exception(struct pt_regs * regs, long interruption_code)
 615{
 616        __u16 __user *location;
 617        int signal = 0;
 618
 619        location = get_check_address(regs);
 620
 621        /*
 622         * We got all needed information from the lowcore and can
 623         * now safely switch on interrupts.
 624         */
 625        if (regs->psw.mask & PSW_MASK_PSTATE)
 626                local_irq_enable();
 627
 628        if (MACHINE_HAS_IEEE)
 629                asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
 630
 631#ifdef CONFIG_MATHEMU
 632        else if (regs->psw.mask & PSW_MASK_PSTATE) {
 633                __u8 opcode[6];
 634                get_user(*((__u16 *) opcode), location);
 635                switch (opcode[0]) {
 636                case 0x28: /* LDR Rx,Ry   */
 637                        signal = math_emu_ldr(opcode);
 638                        break;
 639                case 0x38: /* LER Rx,Ry   */
 640                        signal = math_emu_ler(opcode);
 641                        break;
 642                case 0x60: /* STD R,D(X,B) */
 643                        get_user(*((__u16 *) (opcode+2)), location+1);
 644                        signal = math_emu_std(opcode, regs);
 645                        break;
 646                case 0x68: /* LD R,D(X,B) */
 647                        get_user(*((__u16 *) (opcode+2)), location+1);
 648                        signal = math_emu_ld(opcode, regs);
 649                        break;
 650                case 0x70: /* STE R,D(X,B) */
 651                        get_user(*((__u16 *) (opcode+2)), location+1);
 652                        signal = math_emu_ste(opcode, regs);
 653                        break;
 654                case 0x78: /* LE R,D(X,B) */
 655                        get_user(*((__u16 *) (opcode+2)), location+1);
 656                        signal = math_emu_le(opcode, regs);
 657                        break;
 658                case 0xb3:
 659                        get_user(*((__u16 *) (opcode+2)), location+1);
 660                        signal = math_emu_b3(opcode, regs);
 661                        break;
 662                case 0xed:
 663                        get_user(*((__u32 *) (opcode+2)),
 664                                 (__u32 __user *)(location+1));
 665                        signal = math_emu_ed(opcode, regs);
 666                        break;
 667                case 0xb2:
 668                        if (opcode[1] == 0x99) {
 669                                get_user(*((__u16 *) (opcode+2)), location+1);
 670                                signal = math_emu_srnm(opcode, regs);
 671                        } else if (opcode[1] == 0x9c) {
 672                                get_user(*((__u16 *) (opcode+2)), location+1);
 673                                signal = math_emu_stfpc(opcode, regs);
 674                        } else if (opcode[1] == 0x9d) {
 675                                get_user(*((__u16 *) (opcode+2)), location+1);
 676                                signal = math_emu_lfpc(opcode, regs);
 677                        } else
 678                                signal = SIGILL;
 679                        break;
 680                default:
 681                        signal = SIGILL;
 682                        break;
 683                }
 684        }
 685#endif 
 686        if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
 687                signal = SIGFPE;
 688        else
 689                signal = SIGILL;
 690        if (signal == SIGFPE)
 691                do_fp_trap(regs, location,
 692                           current->thread.fp_regs.fpc, interruption_code);
 693        else if (signal) {
 694                siginfo_t info;
 695                info.si_signo = signal;
 696                info.si_errno = 0;
 697                info.si_code = ILL_ILLOPN;
 698                info.si_addr = location;
 699                do_trap(interruption_code, signal, 
 700                        "data exception", regs, &info);
 701        }
 702}
 703
 704static void space_switch_exception(struct pt_regs * regs, long int_code)
 705{
 706        siginfo_t info;
 707
 708        /* Set user psw back to home space mode. */
 709        if (regs->psw.mask & PSW_MASK_PSTATE)
 710                regs->psw.mask |= PSW_ASC_HOME;
 711        /* Send SIGILL. */
 712        info.si_signo = SIGILL;
 713        info.si_errno = 0;
 714        info.si_code = ILL_PRVOPC;
 715        info.si_addr = get_check_address(regs);
 716        do_trap(int_code, SIGILL, "space switch event", regs, &info);
 717}
 718
 719asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
 720{
 721        bust_spinlocks(1);
 722        printk("Kernel stack overflow.\n");
 723        show_regs(regs);
 724        bust_spinlocks(0);
 725        panic("Corrupt kernel stack, can't continue.");
 726}
 727
 728/* init is done in lowcore.S and head.S */
 729
 730void __init trap_init(void)
 731{
 732        int i;
 733
 734        for (i = 0; i < 128; i++)
 735          pgm_check_table[i] = &default_trap_handler;
 736        pgm_check_table[1] = &illegal_op;
 737        pgm_check_table[2] = &privileged_op;
 738        pgm_check_table[3] = &execute_exception;
 739        pgm_check_table[4] = &do_protection_exception;
 740        pgm_check_table[5] = &addressing_exception;
 741        pgm_check_table[6] = &specification_exception;
 742        pgm_check_table[7] = &data_exception;
 743        pgm_check_table[8] = &overflow_exception;
 744        pgm_check_table[9] = &divide_exception;
 745        pgm_check_table[0x0A] = &overflow_exception;
 746        pgm_check_table[0x0B] = &divide_exception;
 747        pgm_check_table[0x0C] = &hfp_overflow_exception;
 748        pgm_check_table[0x0D] = &hfp_underflow_exception;
 749        pgm_check_table[0x0E] = &hfp_significance_exception;
 750        pgm_check_table[0x0F] = &hfp_divide_exception;
 751        pgm_check_table[0x10] = &do_dat_exception;
 752        pgm_check_table[0x11] = &do_dat_exception;
 753        pgm_check_table[0x12] = &translation_exception;
 754        pgm_check_table[0x13] = &special_op_exception;
 755#ifdef CONFIG_64BIT
 756        pgm_check_table[0x38] = &do_asce_exception;
 757        pgm_check_table[0x39] = &do_dat_exception;
 758        pgm_check_table[0x3A] = &do_dat_exception;
 759        pgm_check_table[0x3B] = &do_dat_exception;
 760#endif /* CONFIG_64BIT */
 761        pgm_check_table[0x15] = &operand_exception;
 762        pgm_check_table[0x1C] = &space_switch_exception;
 763        pgm_check_table[0x1D] = &hfp_sqrt_exception;
 764        pfault_irq_init();
 765}
 766