linux-old/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/config.h>
  18#include <linux/sched.h>
  19#include <linux/kernel.h>
  20#include <linux/string.h>
  21#include <linux/errno.h>
  22#include <linux/ptrace.h>
  23#include <linux/timer.h>
  24#include <linux/mm.h>
  25#include <linux/smp.h>
  26#include <linux/smp_lock.h>
  27#include <linux/init.h>
  28#include <linux/delay.h>
  29#include <linux/module.h>
  30
  31#include <asm/system.h>
  32#include <asm/uaccess.h>
  33#include <asm/io.h>
  34#include <asm/atomic.h>
  35#include <asm/mathemu.h>
  36#include <asm/cpcmd.h>
  37#include <asm/s390_ext.h>
  38
  39/* Called from entry.S only */
  40extern void handle_per_exception(struct pt_regs *regs);
  41
  42typedef void pgm_check_handler_t(struct pt_regs *, long);
  43pgm_check_handler_t *pgm_check_table[128];
  44
  45#ifdef CONFIG_SYSCTL
  46#ifdef CONFIG_PROCESS_DEBUG
  47int sysctl_userprocess_debug = 1;
  48#else
  49int sysctl_userprocess_debug = 0;
  50#endif
  51#endif
  52
  53extern pgm_check_handler_t do_protection_exception;
  54extern pgm_check_handler_t do_segment_exception;
  55extern pgm_check_handler_t do_page_exception;
  56extern pgm_check_handler_t do_pseudo_page_fault;
  57#ifdef CONFIG_PFAULT
  58extern int pfault_init(void);
  59extern void pfault_fini(void);
  60extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
  61static ext_int_info_t ext_int_pfault;
  62#endif
  63
  64int kstack_depth_to_print = 12;
  65
  66/*
  67 * If the address is either in the .text section of the
  68 * kernel, or in the vmalloc'ed module regions, it *may* 
  69 * be the address of a calling routine
  70 */
  71extern char _stext, _etext;
  72
  73#ifdef CONFIG_MODULES
  74
  75extern struct module *module_list;
  76extern struct module kernel_module;
  77
  78static inline int kernel_text_address(unsigned long addr)
  79{
  80        int retval = 0;
  81        struct module *mod;
  82
  83        if (addr >= (unsigned long) &_stext &&
  84            addr <= (unsigned long) &_etext)
  85                return 1;
  86
  87        for (mod = module_list; mod != &kernel_module; mod = mod->next) {
  88                /* mod_bound tests for addr being inside the vmalloc'ed
  89                 * module area. Of course it'd be better to test only
  90                 * for the .text subset... */
  91                if (mod_bound(addr, 0, mod)) {
  92                        retval = 1;
  93                        break;
  94                }
  95        }
  96
  97        return retval;
  98}
  99
 100#else
 101
 102static inline int kernel_text_address(unsigned long addr)
 103{
 104        return (addr >= (unsigned long) &_stext &&
 105                addr <= (unsigned long) &_etext);
 106}
 107
 108#endif
 109
 110void show_trace(unsigned long * stack)
 111{
 112        unsigned long backchain, low_addr, high_addr, ret_addr;
 113        int i;
 114
 115        if (!stack)
 116                stack = (unsigned long*)&stack;
 117
 118        printk("Call Trace: ");
 119        low_addr = ((unsigned long) stack) & PSW_ADDR_MASK;
 120        high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
 121        /* Skip the first frame (biased stack) */
 122        backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK;
 123        /* Print up to 8 lines */
 124        for (i = 0; i < 8; i++) {
 125                if (backchain < low_addr || backchain >= high_addr)
 126                        break;
 127                ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_MASK;
 128                if (!kernel_text_address(ret_addr))
 129                        break;
 130                if (i && ((i % 6) == 0))
 131                        printk("\n   ");
 132                printk("[<%08lx>] ", ret_addr);
 133                low_addr = backchain;
 134                backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK;
 135        }
 136        printk("\n");
 137}
 138
 139void show_trace_task(struct task_struct *tsk)
 140{
 141        /*
 142         * We can't print the backtrace of a running process. It is
 143         * unreliable at best and can cause kernel oopses.
 144         */
 145        if (task_has_cpu(tsk))
 146                return;
 147        show_trace((unsigned long *) tsk->thread.ksp);
 148}
 149
 150void show_stack(unsigned long *sp)
 151{
 152        unsigned long *stack;
 153        int i;
 154
 155        // debugging aid: "show_stack(NULL);" prints the
 156        // back trace for this cpu.
 157
 158        if(sp == NULL)
 159                sp = (unsigned long*) &sp;
 160
 161        stack = sp;
 162        for (i = 0; i < kstack_depth_to_print; i++) {
 163                if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
 164                        break;
 165                if (i && ((i % 8) == 0))
 166                        printk("\n       ");
 167                printk("%08lx ", *stack++);
 168        }
 169        printk("\n");
 170        show_trace(sp);
 171}
 172
 173void show_registers(struct pt_regs *regs)
 174{
 175        mm_segment_t old_fs;
 176        char *mode;
 177        int i;
 178
 179        mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl";
 180        printk("%s PSW : %08lx %08lx\n",
 181               mode, (unsigned long) regs->psw.mask,
 182               (unsigned long) regs->psw.addr);
 183        printk("%s GPRS: %08x %08x %08x %08x\n", mode,
 184               regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
 185        printk("           %08x %08x %08x %08x\n",
 186               regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
 187        printk("           %08x %08x %08x %08x\n",
 188               regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
 189        printk("           %08x %08x %08x %08x\n",
 190               regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
 191        printk("%s ACRS: %08x %08x %08x %08x\n", mode,
 192               regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]);
 193        printk("           %08x %08x %08x %08x\n",
 194               regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]);
 195        printk("           %08x %08x %08x %08x\n",
 196               regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]);
 197        printk("           %08x %08x %08x %08x\n",
 198               regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]);
 199
 200        /*
 201         * Print the first 20 byte of the instruction stream at the
 202         * time of the fault.
 203         */
 204        old_fs = get_fs();
 205        if (regs->psw.mask & PSW_PROBLEM_STATE)
 206                set_fs(USER_DS);
 207        else
 208                set_fs(KERNEL_DS);
 209        printk("%s Code: ", mode);
 210        for (i = 0; i < 20; i++) {
 211                unsigned char c;
 212                if (__get_user(c, (char *)(regs->psw.addr + i))) {
 213                        printk(" Bad PSW.");
 214                        break;
 215                }
 216                printk("%02x ", c);
 217        }
 218        set_fs(old_fs);
 219
 220        printk("\n");
 221}       
 222
 223/* This is called from fs/proc/array.c */
 224char *task_show_regs(struct task_struct *task, char *buffer)
 225{
 226        struct pt_regs *regs;
 227
 228        regs = __KSTK_PTREGS(task);
 229        buffer += sprintf(buffer, "task: %08lx, ksp: %08x\n",
 230                          (unsigned long) task, task->thread.ksp);
 231        buffer += sprintf(buffer, "User PSW : %08lx %08lx\n",
 232                          (unsigned long) regs->psw.mask, 
 233                          (unsigned long) regs->psw.addr);
 234        buffer += sprintf(buffer, "User GPRS: %08x %08x %08x %08x\n",
 235                          regs->gprs[0], regs->gprs[1],
 236                          regs->gprs[2], regs->gprs[3]);
 237        buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
 238                          regs->gprs[4], regs->gprs[5],
 239                          regs->gprs[6], regs->gprs[7]);
 240        buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
 241                          regs->gprs[8], regs->gprs[9],
 242                          regs->gprs[10], regs->gprs[11]);
 243        buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
 244                          regs->gprs[12], regs->gprs[13],
 245                          regs->gprs[14], regs->gprs[15]);
 246        buffer += sprintf(buffer, "User ACRS: %08x %08x %08x %08x\n",
 247                          regs->acrs[0], regs->acrs[1],
 248                          regs->acrs[2], regs->acrs[3]);
 249        buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
 250                          regs->acrs[4], regs->acrs[5],
 251                          regs->acrs[6], regs->acrs[7]);
 252        buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
 253                          regs->acrs[8], regs->acrs[9],
 254                          regs->acrs[10], regs->acrs[11]);
 255        buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
 256                          regs->acrs[12], regs->acrs[13],
 257                          regs->acrs[14], regs->acrs[15]);
 258        return buffer;
 259}
 260
 261spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 262
 263void die(const char * str, struct pt_regs * regs, long err)
 264{
 265        console_verbose();
 266        spin_lock_irq(&die_lock);
 267        bust_spinlocks(1);
 268        printk("%s: %04lx\n", str, err & 0xffff);
 269        show_regs(regs);
 270        bust_spinlocks(0);
 271        spin_unlock_irq(&die_lock);
 272        do_exit(SIGSEGV);
 273}
 274
 275static void inline do_trap(long interruption_code, int signr, char *str,
 276                           struct pt_regs *regs, siginfo_t *info)
 277{
 278        /*
 279         * We got all needed information from the lowcore and can
 280         * now safely switch on interrupts.
 281         */
 282        if (regs->psw.mask & PSW_PROBLEM_STATE)
 283                __sti();
 284
 285        if (regs->psw.mask & PSW_PROBLEM_STATE) {
 286                struct task_struct *tsk = current;
 287
 288                tsk->thread.trap_no = interruption_code & 0xffff;
 289                if (info)
 290                        force_sig_info(signr, info, tsk);
 291                else
 292                        force_sig(signr, tsk);
 293#ifndef CONFIG_SYSCTL
 294#ifdef CONFIG_PROCESS_DEBUG
 295                printk("User process fault: interruption code 0x%lX\n",
 296                       interruption_code);
 297                show_regs(regs);
 298#endif
 299#else
 300                if (sysctl_userprocess_debug) {
 301                        printk("User process fault: interruption code 0x%lX\n",
 302                               interruption_code);
 303                        show_regs(regs);
 304                }
 305#endif
 306        } else {
 307                unsigned long fixup = search_exception_table(regs->psw.addr);
 308                if (fixup)
 309                        regs->psw.addr = fixup;
 310                else
 311                        die(str, regs, interruption_code);
 312        }
 313}
 314
 315static inline void *get_check_address(struct pt_regs *regs)
 316{
 317        return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
 318}
 319
 320int do_debugger_trap(struct pt_regs *regs,int signal)
 321{
 322        if(regs->psw.mask&PSW_PROBLEM_STATE)
 323        {
 324                if(current->ptrace & PT_PTRACED)
 325                        force_sig(signal,current);
 326                else
 327                        return 1;
 328        }
 329        else
 330        {
 331#if CONFIG_REMOTE_DEBUG
 332                if(gdb_stub_initialised)
 333                {
 334                        gdb_stub_handle_exception(regs, signal);
 335                        return 0;
 336                }
 337#endif
 338                return 1;
 339        }
 340        return 0;
 341}
 342
 343#define DO_ERROR(signr, str, name) \
 344asmlinkage void name(struct pt_regs * regs, long interruption_code) \
 345{ \
 346        do_trap(interruption_code, signr, str, regs, NULL); \
 347}
 348
 349#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
 350asmlinkage void name(struct pt_regs * regs, long interruption_code) \
 351{ \
 352        siginfo_t info; \
 353        info.si_signo = signr; \
 354        info.si_errno = 0; \
 355        info.si_code = sicode; \
 356        info.si_addr = (void *)siaddr; \
 357        do_trap(interruption_code, signr, str, regs, &info); \
 358}
 359
 360DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
 361
 362DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception,
 363              BUS_ADRERR, get_check_address(regs))
 364DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
 365              ILL_ILLOPN, get_check_address(regs))
 366DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
 367              FPE_INTDIV, get_check_address(regs))
 368DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
 369              ILL_ILLOPN, get_check_address(regs))
 370DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
 371              ILL_PRVOPC, get_check_address(regs))
 372DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
 373              ILL_ILLOPN, get_check_address(regs))
 374DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
 375              ILL_ILLOPN, get_check_address(regs))
 376
 377static inline void
 378do_fp_trap(struct pt_regs *regs, void *location,
 379           int fpc, long interruption_code)
 380{
 381        siginfo_t si;
 382
 383        si.si_signo = SIGFPE;
 384        si.si_errno = 0;
 385        si.si_addr = location;
 386        si.si_code = 0;
 387        /* FPC[2] is Data Exception Code */
 388        if ((fpc & 0x00000300) == 0) {
 389                /* bits 6 and 7 of DXC are 0 iff IEEE exception */
 390                if (fpc & 0x8000) /* invalid fp operation */
 391                        si.si_code = FPE_FLTINV;
 392                else if (fpc & 0x4000) /* div by 0 */
 393                        si.si_code = FPE_FLTDIV;
 394                else if (fpc & 0x2000) /* overflow */
 395                        si.si_code = FPE_FLTOVF;
 396                else if (fpc & 0x1000) /* underflow */
 397                        si.si_code = FPE_FLTUND;
 398                else if (fpc & 0x0800) /* inexact */
 399                        si.si_code = FPE_FLTRES;
 400        }
 401        current->thread.ieee_instruction_pointer = (addr_t) location;
 402        do_trap(interruption_code, SIGFPE,
 403                "floating point exception", regs, &si);
 404}
 405
 406asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 407{
 408        __u8 opcode[6];
 409        __u16 *location;
 410        int signal = 0;
 411
 412        location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
 413
 414        /*
 415         * We got all needed information from the lowcore and can
 416         * now safely switch on interrupts.
 417         */
 418        if (regs->psw.mask & PSW_PROBLEM_STATE)
 419                __sti();
 420
 421        if (regs->psw.mask & PSW_PROBLEM_STATE)
 422                get_user(*((__u16 *) opcode), location);
 423        else
 424                *((__u16 *)opcode)=*((__u16 *)location);
 425        if (*((__u16 *)opcode)==S390_BREAKPOINT_U16)
 426        {
 427                if(do_debugger_trap(regs,SIGTRAP))
 428                        signal = SIGILL;
 429        }
 430#ifdef CONFIG_MATHEMU
 431        else if (regs->psw.mask & PSW_PROBLEM_STATE)
 432        {
 433                if (opcode[0] == 0xb3) {
 434                        get_user(*((__u16 *) (opcode+2)), location+1);
 435                        signal = math_emu_b3(opcode, regs);
 436                } else if (opcode[0] == 0xed) {
 437                        get_user(*((__u32 *) (opcode+2)),
 438                                 (__u32 *)(location+1));
 439                        signal = math_emu_ed(opcode, regs);
 440                } else if (*((__u16 *) opcode) == 0xb299) {
 441                        get_user(*((__u16 *) (opcode+2)), location+1);
 442                        signal = math_emu_srnm(opcode, regs);
 443                } else if (*((__u16 *) opcode) == 0xb29c) {
 444                        get_user(*((__u16 *) (opcode+2)), location+1);
 445                        signal = math_emu_stfpc(opcode, regs);
 446                } else if (*((__u16 *) opcode) == 0xb29d) {
 447                        get_user(*((__u16 *) (opcode+2)), location+1);
 448                        signal = math_emu_lfpc(opcode, regs);
 449                } else
 450                        signal = SIGILL;
 451        }
 452#endif 
 453        else
 454                signal = SIGILL;
 455        if (signal == SIGFPE)
 456                do_fp_trap(regs, location,
 457                           current->thread.fp_regs.fpc, interruption_code);
 458        else if (signal)
 459                do_trap(interruption_code, signal,
 460                        "illegal operation", regs, NULL);
 461}
 462
 463
 464
 465#ifdef CONFIG_MATHEMU
 466asmlinkage void 
 467specification_exception(struct pt_regs * regs, long interruption_code)
 468{
 469        __u8 opcode[6];
 470        __u16 *location = NULL;
 471        int signal = 0;
 472
 473        location = (__u16 *) get_check_address(regs);
 474
 475        /*
 476         * We got all needed information from the lowcore and can
 477         * now safely switch on interrupts.
 478         */
 479        if (regs->psw.mask & PSW_PROBLEM_STATE)
 480                __sti();
 481                
 482        if (regs->psw.mask & PSW_PROBLEM_STATE) {
 483                get_user(*((__u16 *) opcode), location);
 484                switch (opcode[0]) {
 485                case 0x28: /* LDR Rx,Ry   */
 486                        signal = math_emu_ldr(opcode);
 487                        break;
 488                case 0x38: /* LER Rx,Ry   */
 489                        signal = math_emu_ler(opcode);
 490                        break;
 491                case 0x60: /* STD R,D(X,B) */
 492                        get_user(*((__u16 *) (opcode+2)), location+1);
 493                        signal = math_emu_std(opcode, regs);
 494                        break;
 495                case 0x68: /* LD R,D(X,B) */
 496                        get_user(*((__u16 *) (opcode+2)), location+1);
 497                        signal = math_emu_ld(opcode, regs);
 498                        break;
 499                case 0x70: /* STE R,D(X,B) */
 500                        get_user(*((__u16 *) (opcode+2)), location+1);
 501                        signal = math_emu_ste(opcode, regs);
 502                        break;
 503                case 0x78: /* LE R,D(X,B) */
 504                        get_user(*((__u16 *) (opcode+2)), location+1);
 505                        signal = math_emu_le(opcode, regs);
 506                        break;
 507                default:
 508                        signal = SIGILL;
 509                        break;
 510                }
 511        } else
 512                signal = SIGILL;
 513        if (signal == SIGFPE)
 514                do_fp_trap(regs, location,
 515                           current->thread.fp_regs.fpc, interruption_code);
 516        else if (signal) {
 517                siginfo_t info;
 518                info.si_signo = signal;
 519                info.si_errno = 0;
 520                info.si_code = ILL_ILLOPN;
 521                info.si_addr = location;
 522                do_trap(interruption_code, signal, 
 523                        "specification exception", regs, &info);
 524        }
 525}
 526#else
 527DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
 528              ILL_ILLOPN, get_check_address(regs));
 529#endif
 530
 531asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 532{
 533        __u8 opcode[6];
 534        __u16 *location;
 535        int signal = 0;
 536
 537        location = (__u16 *) get_check_address(regs);
 538
 539        /*
 540         * We got all needed information from the lowcore and can
 541         * now safely switch on interrupts.
 542         */
 543        if (regs->psw.mask & PSW_PROBLEM_STATE)
 544                __sti();
 545
 546        if (MACHINE_HAS_IEEE)
 547                __asm__ volatile ("stfpc %0\n\t" 
 548                                  : "=m" (current->thread.fp_regs.fpc));
 549
 550#ifdef CONFIG_MATHEMU
 551        else if (regs->psw.mask & PSW_PROBLEM_STATE) {
 552                get_user(*((__u16 *) opcode), location);
 553                switch (opcode[0]) {
 554                case 0x28: /* LDR Rx,Ry   */
 555                        signal = math_emu_ldr(opcode);
 556                        break;
 557                case 0x38: /* LER Rx,Ry   */
 558                        signal = math_emu_ler(opcode);
 559                        break;
 560                case 0x60: /* STD R,D(X,B) */
 561                        get_user(*((__u16 *) (opcode+2)), location+1);
 562                        signal = math_emu_std(opcode, regs);
 563                        break;
 564                case 0x68: /* LD R,D(X,B) */
 565                        get_user(*((__u16 *) (opcode+2)), location+1);
 566                        signal = math_emu_ld(opcode, regs);
 567                        break;
 568                case 0x70: /* STE R,D(X,B) */
 569                        get_user(*((__u16 *) (opcode+2)), location+1);
 570                        signal = math_emu_ste(opcode, regs);
 571                        break;
 572                case 0x78: /* LE R,D(X,B) */
 573                        get_user(*((__u16 *) (opcode+2)), location+1);
 574                        signal = math_emu_le(opcode, regs);
 575                        break;
 576                case 0xb3:
 577                        get_user(*((__u16 *) (opcode+2)), location+1);
 578                        signal = math_emu_b3(opcode, regs);
 579                        break;
 580                case 0xed:
 581                        get_user(*((__u32 *) (opcode+2)),
 582                                 (__u32 *)(location+1));
 583                        signal = math_emu_ed(opcode, regs);
 584                        break;
 585                case 0xb2:
 586                        if (opcode[1] == 0x99) {
 587                                get_user(*((__u16 *) (opcode+2)), location+1);
 588                                signal = math_emu_srnm(opcode, regs);
 589                        } else if (opcode[1] == 0x9c) {
 590                                get_user(*((__u16 *) (opcode+2)), location+1);
 591                                signal = math_emu_stfpc(opcode, regs);
 592                        } else if (opcode[1] == 0x9d) {
 593                                get_user(*((__u16 *) (opcode+2)), location+1);
 594                                signal = math_emu_lfpc(opcode, regs);
 595                        } else
 596                                signal = SIGILL;
 597                        break;
 598                default:
 599                        signal = SIGILL;
 600                        break;
 601                }
 602        }
 603#endif 
 604        if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
 605                signal = SIGFPE;
 606        else
 607                signal = SIGILL;
 608        if (signal == SIGFPE)
 609                do_fp_trap(regs, location,
 610                           current->thread.fp_regs.fpc, interruption_code);
 611        else if (signal) {
 612                siginfo_t info;
 613                info.si_signo = signal;
 614                info.si_errno = 0;
 615                info.si_code = ILL_ILLOPN;
 616                info.si_addr = location;
 617                do_trap(interruption_code, signal, 
 618                        "data exception", regs, &info);
 619        }
 620}
 621
 622
 623
 624/* init is done in lowcore.S and head.S */
 625
 626void __init trap_init(void)
 627{
 628        int i;
 629
 630        for (i = 0; i < 128; i++)
 631          pgm_check_table[i] = &default_trap_handler;
 632        pgm_check_table[1] = &illegal_op;
 633        pgm_check_table[2] = &privileged_op;
 634        pgm_check_table[3] = &execute_exception;
 635        pgm_check_table[4] = &do_protection_exception;
 636        pgm_check_table[5] = &addressing_exception;
 637        pgm_check_table[6] = &specification_exception;
 638        pgm_check_table[7] = &data_exception;
 639        pgm_check_table[9] = &divide_exception;
 640        pgm_check_table[0x10] = &do_segment_exception;
 641        pgm_check_table[0x11] = &do_page_exception;
 642        pgm_check_table[0x12] = &translation_exception;
 643        pgm_check_table[0x13] = &special_op_exception;
 644        pgm_check_table[0x14] = &do_pseudo_page_fault;
 645        pgm_check_table[0x15] = &operand_exception;
 646        pgm_check_table[0x1C] = &privileged_op;
 647#ifdef CONFIG_PFAULT
 648        if (MACHINE_IS_VM) {
 649                /* request the 0x2603 external interrupt */
 650                if (register_early_external_interrupt(0x2603, pfault_interrupt,
 651                                                      &ext_int_pfault) != 0)
 652                        panic("Couldn't request external interrupt 0x2603");
 653                /*
 654                 * First try to get pfault pseudo page faults going.
 655                 * If this isn't available turn on pagex page faults.
 656                 */
 657                if (pfault_init() != 0) {
 658                        /* Tough luck, no pfault. */
 659                        unregister_early_external_interrupt(0x2603,
 660                                                            pfault_interrupt,
 661                                                            &ext_int_pfault);
 662                        cpcmd("SET PAGEX ON", NULL, 0);
 663                }
 664        }
 665#else
 666        if (MACHINE_IS_VM)
 667                cpcmd("SET PAGEX ON", NULL, 0);
 668#endif
 669}
 670
 671
 672void handle_per_exception(struct pt_regs *regs)
 673{
 674        if(regs->psw.mask&PSW_PROBLEM_STATE)
 675        {
 676                per_struct *per_info=&current->thread.per_info;
 677                per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
 678                per_info->lowcore.words.address=S390_lowcore.per_address;
 679                per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
 680        }
 681        if(do_debugger_trap(regs,SIGTRAP))
 682        {
 683                /* I've seen this possibly a task structure being reused ? */
 684                printk("Spurious per exception detected\n");
 685                printk("switching off per tracing for this task.\n");
 686                show_regs(regs);
 687                /* Hopefully switching off per tracing will help us survive */
 688                regs->psw.mask &= ~PSW_PER_MASK;
 689        }
 690}
 691
 692
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.