aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/traps.c')
-rw-r--r--arch/s390/kernel/traps.c222
1 files changed, 79 insertions, 143 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 5d8f0f3d0250..a65d2e82f61d 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -39,7 +39,6 @@
39#include <asm/atomic.h> 39#include <asm/atomic.h>
40#include <asm/mathemu.h> 40#include <asm/mathemu.h>
41#include <asm/cpcmd.h> 41#include <asm/cpcmd.h>
42#include <asm/s390_ext.h>
43#include <asm/lowcore.h> 42#include <asm/lowcore.h>
44#include <asm/debug.h> 43#include <asm/debug.h>
45#include "entry.h" 44#include "entry.h"
@@ -237,43 +236,6 @@ void show_regs(struct pt_regs *regs)
237 show_last_breaking_event(regs); 236 show_last_breaking_event(regs);
238} 237}
239 238
240/* This is called from fs/proc/array.c */
241void task_show_regs(struct seq_file *m, struct task_struct *task)
242{
243 struct pt_regs *regs;
244
245 regs = task_pt_regs(task);
246 seq_printf(m, "task: %p, ksp: %p\n",
247 task, (void *)task->thread.ksp);
248 seq_printf(m, "User PSW : %p %p\n",
249 (void *) regs->psw.mask, (void *)regs->psw.addr);
250
251 seq_printf(m, "User GPRS: " FOURLONG,
252 regs->gprs[0], regs->gprs[1],
253 regs->gprs[2], regs->gprs[3]);
254 seq_printf(m, " " FOURLONG,
255 regs->gprs[4], regs->gprs[5],
256 regs->gprs[6], regs->gprs[7]);
257 seq_printf(m, " " FOURLONG,
258 regs->gprs[8], regs->gprs[9],
259 regs->gprs[10], regs->gprs[11]);
260 seq_printf(m, " " FOURLONG,
261 regs->gprs[12], regs->gprs[13],
262 regs->gprs[14], regs->gprs[15]);
263 seq_printf(m, "User ACRS: %08x %08x %08x %08x\n",
264 task->thread.acrs[0], task->thread.acrs[1],
265 task->thread.acrs[2], task->thread.acrs[3]);
266 seq_printf(m, " %08x %08x %08x %08x\n",
267 task->thread.acrs[4], task->thread.acrs[5],
268 task->thread.acrs[6], task->thread.acrs[7]);
269 seq_printf(m, " %08x %08x %08x %08x\n",
270 task->thread.acrs[8], task->thread.acrs[9],
271 task->thread.acrs[10], task->thread.acrs[11]);
272 seq_printf(m, " %08x %08x %08x %08x\n",
273 task->thread.acrs[12], task->thread.acrs[13],
274 task->thread.acrs[14], task->thread.acrs[15]);
275}
276
277static DEFINE_SPINLOCK(die_lock); 239static DEFINE_SPINLOCK(die_lock);
278 240
279void die(const char * str, struct pt_regs * regs, long err) 241void die(const char * str, struct pt_regs * regs, long err)
@@ -329,27 +291,19 @@ int is_valid_bugaddr(unsigned long addr)
329 return 1; 291 return 1;
330} 292}
331 293
332static void __kprobes inline do_trap(long interruption_code, int signr, 294static inline void __kprobes do_trap(long pgm_int_code, int signr, char *str,
333 char *str, struct pt_regs *regs, 295 struct pt_regs *regs, siginfo_t *info)
334 siginfo_t *info)
335{ 296{
336 /* 297 if (notify_die(DIE_TRAP, str, regs, pgm_int_code,
337 * We got all needed information from the lowcore and can 298 pgm_int_code, signr) == NOTIFY_STOP)
338 * now safely switch on interrupts.
339 */
340 if (regs->psw.mask & PSW_MASK_PSTATE)
341 local_irq_enable();
342
343 if (notify_die(DIE_TRAP, str, regs, interruption_code,
344 interruption_code, signr) == NOTIFY_STOP)
345 return; 299 return;
346 300
347 if (regs->psw.mask & PSW_MASK_PSTATE) { 301 if (regs->psw.mask & PSW_MASK_PSTATE) {
348 struct task_struct *tsk = current; 302 struct task_struct *tsk = current;
349 303
350 tsk->thread.trap_no = interruption_code & 0xffff; 304 tsk->thread.trap_no = pgm_int_code & 0xffff;
351 force_sig_info(signr, info, tsk); 305 force_sig_info(signr, info, tsk);
352 report_user_fault(regs, interruption_code, signr); 306 report_user_fault(regs, pgm_int_code, signr);
353 } else { 307 } else {
354 const struct exception_table_entry *fixup; 308 const struct exception_table_entry *fixup;
355 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); 309 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
@@ -361,77 +315,77 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
361 btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs); 315 btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
362 if (btt == BUG_TRAP_TYPE_WARN) 316 if (btt == BUG_TRAP_TYPE_WARN)
363 return; 317 return;
364 die(str, regs, interruption_code); 318 die(str, regs, pgm_int_code);
365 } 319 }
366 } 320 }
367} 321}
368 322
369static inline void __user *get_check_address(struct pt_regs *regs) 323static inline void __user *get_psw_address(struct pt_regs *regs,
324 long pgm_int_code)
370{ 325{
371 return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN); 326 return (void __user *)
327 ((regs->psw.addr - (pgm_int_code >> 16)) & PSW_ADDR_INSN);
372} 328}
373 329
374void __kprobes do_single_step(struct pt_regs *regs) 330void __kprobes do_per_trap(struct pt_regs *regs)
375{ 331{
376 if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, 332 if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
377 SIGTRAP) == NOTIFY_STOP){
378 return; 333 return;
379 }
380 if (tracehook_consider_fatal_signal(current, SIGTRAP)) 334 if (tracehook_consider_fatal_signal(current, SIGTRAP))
381 force_sig(SIGTRAP, current); 335 force_sig(SIGTRAP, current);
382} 336}
383 337
384static void default_trap_handler(struct pt_regs * regs, long interruption_code) 338static void default_trap_handler(struct pt_regs *regs, long pgm_int_code,
339 unsigned long trans_exc_code)
385{ 340{
386 if (regs->psw.mask & PSW_MASK_PSTATE) { 341 if (regs->psw.mask & PSW_MASK_PSTATE) {
387 local_irq_enable(); 342 report_user_fault(regs, pgm_int_code, SIGSEGV);
388 report_user_fault(regs, interruption_code, SIGSEGV);
389 do_exit(SIGSEGV); 343 do_exit(SIGSEGV);
390 } else 344 } else
391 die("Unknown program exception", regs, interruption_code); 345 die("Unknown program exception", regs, pgm_int_code);
392} 346}
393 347
394#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ 348#define DO_ERROR_INFO(name, signr, sicode, str) \
395static void name(struct pt_regs * regs, long interruption_code) \ 349static void name(struct pt_regs *regs, long pgm_int_code, \
350 unsigned long trans_exc_code) \
396{ \ 351{ \
397 siginfo_t info; \ 352 siginfo_t info; \
398 info.si_signo = signr; \ 353 info.si_signo = signr; \
399 info.si_errno = 0; \ 354 info.si_errno = 0; \
400 info.si_code = sicode; \ 355 info.si_code = sicode; \
401 info.si_addr = siaddr; \ 356 info.si_addr = get_psw_address(regs, pgm_int_code); \
402 do_trap(interruption_code, signr, str, regs, &info); \ 357 do_trap(pgm_int_code, signr, str, regs, &info); \
403} 358}
404 359
405DO_ERROR_INFO(SIGILL, "addressing exception", addressing_exception, 360DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
406 ILL_ILLADR, get_check_address(regs)) 361 "addressing exception")
407DO_ERROR_INFO(SIGILL, "execute exception", execute_exception, 362DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
408 ILL_ILLOPN, get_check_address(regs)) 363 "execute exception")
409DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception, 364DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
410 FPE_INTDIV, get_check_address(regs)) 365 "fixpoint divide exception")
411DO_ERROR_INFO(SIGFPE, "fixpoint overflow exception", overflow_exception, 366DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
412 FPE_INTOVF, get_check_address(regs)) 367 "fixpoint overflow exception")
413DO_ERROR_INFO(SIGFPE, "HFP overflow exception", hfp_overflow_exception, 368DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
414 FPE_FLTOVF, get_check_address(regs)) 369 "HFP overflow exception")
415DO_ERROR_INFO(SIGFPE, "HFP underflow exception", hfp_underflow_exception, 370DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
416 FPE_FLTUND, get_check_address(regs)) 371 "HFP underflow exception")
417DO_ERROR_INFO(SIGFPE, "HFP significance exception", hfp_significance_exception, 372DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
418 FPE_FLTRES, get_check_address(regs)) 373 "HFP significance exception")
419DO_ERROR_INFO(SIGFPE, "HFP divide exception", hfp_divide_exception, 374DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
420 FPE_FLTDIV, get_check_address(regs)) 375 "HFP divide exception")
421DO_ERROR_INFO(SIGFPE, "HFP square root exception", hfp_sqrt_exception, 376DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
422 FPE_FLTINV, get_check_address(regs)) 377 "HFP square root exception")
423DO_ERROR_INFO(SIGILL, "operand exception", operand_exception, 378DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
424 ILL_ILLOPN, get_check_address(regs)) 379 "operand exception")
425DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op, 380DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
426 ILL_PRVOPC, get_check_address(regs)) 381 "privileged operation")
427DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception, 382DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
428 ILL_ILLOPN, get_check_address(regs)) 383 "special operation exception")
429DO_ERROR_INFO(SIGILL, "translation exception", translation_exception, 384DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN,
430 ILL_ILLOPN, get_check_address(regs)) 385 "translation exception")
431 386
432static inline void 387static inline void do_fp_trap(struct pt_regs *regs, void __user *location,
433do_fp_trap(struct pt_regs *regs, void __user *location, 388 int fpc, long pgm_int_code)
434 int fpc, long interruption_code)
435{ 389{
436 siginfo_t si; 390 siginfo_t si;
437 391
@@ -453,26 +407,19 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
453 else if (fpc & 0x0800) /* inexact */ 407 else if (fpc & 0x0800) /* inexact */
454 si.si_code = FPE_FLTRES; 408 si.si_code = FPE_FLTRES;
455 } 409 }
456 current->thread.ieee_instruction_pointer = (addr_t) location; 410 do_trap(pgm_int_code, SIGFPE,
457 do_trap(interruption_code, SIGFPE,
458 "floating point exception", regs, &si); 411 "floating point exception", regs, &si);
459} 412}
460 413
461static void illegal_op(struct pt_regs * regs, long interruption_code) 414static void __kprobes illegal_op(struct pt_regs *regs, long pgm_int_code,
415 unsigned long trans_exc_code)
462{ 416{
463 siginfo_t info; 417 siginfo_t info;
464 __u8 opcode[6]; 418 __u8 opcode[6];
465 __u16 __user *location; 419 __u16 __user *location;
466 int signal = 0; 420 int signal = 0;
467 421
468 location = get_check_address(regs); 422 location = get_psw_address(regs, pgm_int_code);
469
470 /*
471 * We got all needed information from the lowcore and can
472 * now safely switch on interrupts.
473 */
474 if (regs->psw.mask & PSW_MASK_PSTATE)
475 local_irq_enable();
476 423
477 if (regs->psw.mask & PSW_MASK_PSTATE) { 424 if (regs->psw.mask & PSW_MASK_PSTATE) {
478 if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) 425 if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
@@ -512,7 +459,7 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
512 * If we get an illegal op in kernel mode, send it through the 459 * If we get an illegal op in kernel mode, send it through the
513 * kprobes notifier. If kprobes doesn't pick it up, SIGILL 460 * kprobes notifier. If kprobes doesn't pick it up, SIGILL
514 */ 461 */
515 if (notify_die(DIE_BPT, "bpt", regs, interruption_code, 462 if (notify_die(DIE_BPT, "bpt", regs, pgm_int_code,
516 3, SIGTRAP) != NOTIFY_STOP) 463 3, SIGTRAP) != NOTIFY_STOP)
517 signal = SIGILL; 464 signal = SIGILL;
518 } 465 }
@@ -520,13 +467,13 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
520#ifdef CONFIG_MATHEMU 467#ifdef CONFIG_MATHEMU
521 if (signal == SIGFPE) 468 if (signal == SIGFPE)
522 do_fp_trap(regs, location, 469 do_fp_trap(regs, location,
523 current->thread.fp_regs.fpc, interruption_code); 470 current->thread.fp_regs.fpc, pgm_int_code);
524 else if (signal == SIGSEGV) { 471 else if (signal == SIGSEGV) {
525 info.si_signo = signal; 472 info.si_signo = signal;
526 info.si_errno = 0; 473 info.si_errno = 0;
527 info.si_code = SEGV_MAPERR; 474 info.si_code = SEGV_MAPERR;
528 info.si_addr = (void __user *) location; 475 info.si_addr = (void __user *) location;
529 do_trap(interruption_code, signal, 476 do_trap(pgm_int_code, signal,
530 "user address fault", regs, &info); 477 "user address fault", regs, &info);
531 } else 478 } else
532#endif 479#endif
@@ -535,28 +482,22 @@ static void illegal_op(struct pt_regs * regs, long interruption_code)
535 info.si_errno = 0; 482 info.si_errno = 0;
536 info.si_code = ILL_ILLOPC; 483 info.si_code = ILL_ILLOPC;
537 info.si_addr = (void __user *) location; 484 info.si_addr = (void __user *) location;
538 do_trap(interruption_code, signal, 485 do_trap(pgm_int_code, signal,
539 "illegal operation", regs, &info); 486 "illegal operation", regs, &info);
540 } 487 }
541} 488}
542 489
543 490
544#ifdef CONFIG_MATHEMU 491#ifdef CONFIG_MATHEMU
545asmlinkage void 492asmlinkage void specification_exception(struct pt_regs *regs,
546specification_exception(struct pt_regs * regs, long interruption_code) 493 long pgm_int_code,
494 unsigned long trans_exc_code)
547{ 495{
548 __u8 opcode[6]; 496 __u8 opcode[6];
549 __u16 __user *location = NULL; 497 __u16 __user *location = NULL;
550 int signal = 0; 498 int signal = 0;
551 499
552 location = (__u16 __user *) get_check_address(regs); 500 location = (__u16 __user *) get_psw_address(regs, pgm_int_code);
553
554 /*
555 * We got all needed information from the lowcore and can
556 * now safely switch on interrupts.
557 */
558 if (regs->psw.mask & PSW_MASK_PSTATE)
559 local_irq_enable();
560 501
561 if (regs->psw.mask & PSW_MASK_PSTATE) { 502 if (regs->psw.mask & PSW_MASK_PSTATE) {
562 get_user(*((__u16 *) opcode), location); 503 get_user(*((__u16 *) opcode), location);
@@ -592,35 +533,29 @@ specification_exception(struct pt_regs * regs, long interruption_code)
592 533
593 if (signal == SIGFPE) 534 if (signal == SIGFPE)
594 do_fp_trap(regs, location, 535 do_fp_trap(regs, location,
595 current->thread.fp_regs.fpc, interruption_code); 536 current->thread.fp_regs.fpc, pgm_int_code);
596 else if (signal) { 537 else if (signal) {
597 siginfo_t info; 538 siginfo_t info;
598 info.si_signo = signal; 539 info.si_signo = signal;
599 info.si_errno = 0; 540 info.si_errno = 0;
600 info.si_code = ILL_ILLOPN; 541 info.si_code = ILL_ILLOPN;
601 info.si_addr = location; 542 info.si_addr = location;
602 do_trap(interruption_code, signal, 543 do_trap(pgm_int_code, signal,
603 "specification exception", regs, &info); 544 "specification exception", regs, &info);
604 } 545 }
605} 546}
606#else 547#else
607DO_ERROR_INFO(SIGILL, "specification exception", specification_exception, 548DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
608 ILL_ILLOPN, get_check_address(regs)); 549 "specification exception");
609#endif 550#endif
610 551
611static void data_exception(struct pt_regs * regs, long interruption_code) 552static void data_exception(struct pt_regs *regs, long pgm_int_code,
553 unsigned long trans_exc_code)
612{ 554{
613 __u16 __user *location; 555 __u16 __user *location;
614 int signal = 0; 556 int signal = 0;
615 557
616 location = get_check_address(regs); 558 location = get_psw_address(regs, pgm_int_code);
617
618 /*
619 * We got all needed information from the lowcore and can
620 * now safely switch on interrupts.
621 */
622 if (regs->psw.mask & PSW_MASK_PSTATE)
623 local_irq_enable();
624 559
625 if (MACHINE_HAS_IEEE) 560 if (MACHINE_HAS_IEEE)
626 asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); 561 asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
@@ -686,19 +621,19 @@ static void data_exception(struct pt_regs * regs, long interruption_code)
686 signal = SIGILL; 621 signal = SIGILL;
687 if (signal == SIGFPE) 622 if (signal == SIGFPE)
688 do_fp_trap(regs, location, 623 do_fp_trap(regs, location,
689 current->thread.fp_regs.fpc, interruption_code); 624 current->thread.fp_regs.fpc, pgm_int_code);
690 else if (signal) { 625 else if (signal) {
691 siginfo_t info; 626 siginfo_t info;
692 info.si_signo = signal; 627 info.si_signo = signal;
693 info.si_errno = 0; 628 info.si_errno = 0;
694 info.si_code = ILL_ILLOPN; 629 info.si_code = ILL_ILLOPN;
695 info.si_addr = location; 630 info.si_addr = location;
696 do_trap(interruption_code, signal, 631 do_trap(pgm_int_code, signal, "data exception", regs, &info);
697 "data exception", regs, &info);
698 } 632 }
699} 633}
700 634
701static void space_switch_exception(struct pt_regs * regs, long int_code) 635static void space_switch_exception(struct pt_regs *regs, long pgm_int_code,
636 unsigned long trans_exc_code)
702{ 637{
703 siginfo_t info; 638 siginfo_t info;
704 639
@@ -709,11 +644,11 @@ static void space_switch_exception(struct pt_regs * regs, long int_code)
709 info.si_signo = SIGILL; 644 info.si_signo = SIGILL;
710 info.si_errno = 0; 645 info.si_errno = 0;
711 info.si_code = ILL_PRVOPC; 646 info.si_code = ILL_PRVOPC;
712 info.si_addr = get_check_address(regs); 647 info.si_addr = get_psw_address(regs, pgm_int_code);
713 do_trap(int_code, SIGILL, "space switch event", regs, &info); 648 do_trap(pgm_int_code, SIGILL, "space switch event", regs, &info);
714} 649}
715 650
716asmlinkage void kernel_stack_overflow(struct pt_regs * regs) 651asmlinkage void __kprobes kernel_stack_overflow(struct pt_regs * regs)
717{ 652{
718 bust_spinlocks(1); 653 bust_spinlocks(1);
719 printk("Kernel stack overflow.\n"); 654 printk("Kernel stack overflow.\n");
@@ -758,5 +693,6 @@ void __init trap_init(void)
758 pgm_check_table[0x15] = &operand_exception; 693 pgm_check_table[0x15] = &operand_exception;
759 pgm_check_table[0x1C] = &space_switch_exception; 694 pgm_check_table[0x1C] = &space_switch_exception;
760 pgm_check_table[0x1D] = &hfp_sqrt_exception; 695 pgm_check_table[0x1D] = &hfp_sqrt_exception;
761 pfault_irq_init(); 696 /* Enable machine checks early. */
697 local_mcck_enable();
762} 698}