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