2 * arch/s390/kernel/traps.c
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),
9 * Derived from "arch/i386/kernel/traps.c"
10 * Copyright (C) 1991, 1992 Linus Torvalds
14 * 'Traps.c' handles hardware traps and faults after we have saved some
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>
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 #include <linux/kallsyms.h>
32 #include <asm/system.h>
33 #include <asm/uaccess.h>
35 #include <asm/atomic.h>
36 #include <asm/mathemu.h>
37 #include <asm/cpcmd.h>
38 #include <asm/s390_ext.h>
39 #include <asm/lowcore.h>
41 /* Called from entry.S only */
42 extern void handle_per_exception(struct pt_regs
*regs
);
44 typedef void pgm_check_handler_t(struct pt_regs
*, long);
45 pgm_check_handler_t
*pgm_check_table
[128];
48 #ifdef CONFIG_PROCESS_DEBUG
49 int sysctl_userprocess_debug
= 1;
51 int sysctl_userprocess_debug
= 0;
55 extern pgm_check_handler_t do_protection_exception
;
56 extern pgm_check_handler_t do_segment_exception
;
57 extern pgm_check_handler_t do_region_exception
;
58 extern pgm_check_handler_t do_page_exception
;
59 extern pgm_check_handler_t do_pseudo_page_fault
;
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
;
67 #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; })
69 #ifndef CONFIG_ARCH_S390X
71 #define FOURLONG "%08lx %08lx %08lx %08lx\n"
72 static int kstack_depth_to_print
= 12;
74 #else /* CONFIG_ARCH_S390X */
76 #define FOURLONG "%016lx %016lx %016lx %016lx\n"
77 static int kstack_depth_to_print
= 20;
79 #endif /* CONFIG_ARCH_S390X */
81 void show_trace(struct task_struct
*task
, unsigned long * stack
)
83 unsigned long backchain
, low_addr
, high_addr
, ret_addr
;
86 stack
= *stack_pointer
;
88 printk("Call Trace:\n");
89 low_addr
= ((unsigned long) stack
) & PSW_ADDR_INSN
;
90 high_addr
= (low_addr
& (-THREAD_SIZE
)) + THREAD_SIZE
;
91 /* Skip the first frame (biased stack) */
92 backchain
= *((unsigned long *) low_addr
) & PSW_ADDR_INSN
;
93 /* Print up to 8 lines */
94 while (backchain
> low_addr
&& backchain
<= high_addr
) {
95 ret_addr
= *((unsigned long *) (backchain
+RET_ADDR
)) & PSW_ADDR_INSN
;
96 printk(" [<%016lx>] ", ret_addr
);
97 print_symbol("%s\n", ret_addr
);
99 backchain
= *((unsigned long *) backchain
) & PSW_ADDR_INSN
;
104 void show_trace_task(struct task_struct
*tsk
)
107 * We can't print the backtrace of a running process. It is
108 * unreliable at best and can cause kernel oopses.
110 if (tsk
->state
== TASK_RUNNING
)
112 show_trace(tsk
, (unsigned long *) tsk
->thread
.ksp
);
115 void show_stack(struct task_struct
*task
, unsigned long *sp
)
117 unsigned long *stack
;
120 // debugging aid: "show_stack(NULL);" prints the
121 // back trace for this cpu.
127 for (i
= 0; i
< kstack_depth_to_print
; i
++) {
128 if (((addr_t
) stack
& (THREAD_SIZE
-1)) == 0)
130 if (i
&& ((i
* sizeof (long) % 32) == 0))
132 printk("%p ", (void *)*stack
++);
135 show_trace(task
, sp
);
139 * The architecture-independent dump_stack generator
141 void dump_stack(void)
143 show_stack(current
, 0);
146 void show_registers(struct pt_regs
*regs
)
152 mode
= (regs
->psw
.mask
& PSW_MASK_PSTATE
) ? "User" : "Krnl";
153 printk("%s PSW : %p %p\n",
154 mode
, (void *) regs
->psw
.mask
,
155 (void *) regs
->psw
.addr
);
156 printk("%s GPRS: " FOURLONG
, mode
,
157 regs
->gprs
[0], regs
->gprs
[1], regs
->gprs
[2], regs
->gprs
[3]);
159 regs
->gprs
[4], regs
->gprs
[5], regs
->gprs
[6], regs
->gprs
[7]);
161 regs
->gprs
[8], regs
->gprs
[9], regs
->gprs
[10], regs
->gprs
[11]);
163 regs
->gprs
[12], regs
->gprs
[13], regs
->gprs
[14], regs
->gprs
[15]);
165 printk("%s ACRS: %08x %08x %08x %08x\n", mode
,
166 regs
->acrs
[0], regs
->acrs
[1], regs
->acrs
[2], regs
->acrs
[3]);
167 printk(" %08x %08x %08x %08x\n",
168 regs
->acrs
[4], regs
->acrs
[5], regs
->acrs
[6], regs
->acrs
[7]);
169 printk(" %08x %08x %08x %08x\n",
170 regs
->acrs
[8], regs
->acrs
[9], regs
->acrs
[10], regs
->acrs
[11]);
171 printk(" %08x %08x %08x %08x\n",
172 regs
->acrs
[12], regs
->acrs
[13], regs
->acrs
[14], regs
->acrs
[15]);
175 * Print the first 20 byte of the instruction stream at the
179 if (regs
->psw
.mask
& PSW_MASK_PSTATE
)
183 printk("%s Code: ", mode
);
184 for (i
= 0; i
< 20; i
++) {
186 if (__get_user(c
, (char *)(regs
->psw
.addr
+ i
))) {
197 /* This is called from fs/proc/array.c */
198 char *task_show_regs(struct task_struct
*task
, char *buffer
)
200 struct pt_regs
*regs
;
202 regs
= __KSTK_PTREGS(task
);
203 buffer
+= sprintf(buffer
, "task: %p, ksp: %p\n",
204 task
, (void *)task
->thread
.ksp
);
205 buffer
+= sprintf(buffer
, "User PSW : %p %p\n",
206 (void *) regs
->psw
.mask
, (void *)regs
->psw
.addr
);
208 buffer
+= sprintf(buffer
, "User GPRS: " FOURLONG
,
209 regs
->gprs
[0], regs
->gprs
[1],
210 regs
->gprs
[2], regs
->gprs
[3]);
211 buffer
+= sprintf(buffer
, " " FOURLONG
,
212 regs
->gprs
[4], regs
->gprs
[5],
213 regs
->gprs
[6], regs
->gprs
[7]);
214 buffer
+= sprintf(buffer
, " " FOURLONG
,
215 regs
->gprs
[8], regs
->gprs
[9],
216 regs
->gprs
[10], regs
->gprs
[11]);
217 buffer
+= sprintf(buffer
, " " FOURLONG
,
218 regs
->gprs
[12], regs
->gprs
[13],
219 regs
->gprs
[14], regs
->gprs
[15]);
220 buffer
+= sprintf(buffer
, "User ACRS: %08x %08x %08x %08x\n",
221 regs
->acrs
[0], regs
->acrs
[1],
222 regs
->acrs
[2], regs
->acrs
[3]);
223 buffer
+= sprintf(buffer
, " %08x %08x %08x %08x\n",
224 regs
->acrs
[4], regs
->acrs
[5],
225 regs
->acrs
[6], regs
->acrs
[7]);
226 buffer
+= sprintf(buffer
, " %08x %08x %08x %08x\n",
227 regs
->acrs
[8], regs
->acrs
[9],
228 regs
->acrs
[10], regs
->acrs
[11]);
229 buffer
+= sprintf(buffer
, " %08x %08x %08x %08x\n",
230 regs
->acrs
[12], regs
->acrs
[13],
231 regs
->acrs
[14], regs
->acrs
[15]);
235 spinlock_t die_lock
= SPIN_LOCK_UNLOCKED
;
237 void die(const char * str
, struct pt_regs
* regs
, long err
)
239 static int die_counter
;
241 spin_lock_irq(&die_lock
);
243 printk("%s: %04lx [#%d]\n", str
, err
& 0xffff, ++die_counter
);
246 spin_unlock_irq(&die_lock
);
250 static void inline do_trap(long interruption_code
, int signr
, char *str
,
251 struct pt_regs
*regs
, siginfo_t
*info
)
254 * We got all needed information from the lowcore and can
255 * now safely switch on interrupts.
257 if (regs
->psw
.mask
& PSW_MASK_PSTATE
)
260 if (regs
->psw
.mask
& PSW_MASK_PSTATE
) {
261 struct task_struct
*tsk
= current
;
263 tsk
->thread
.trap_no
= interruption_code
& 0xffff;
265 force_sig_info(signr
, info
, tsk
);
267 force_sig(signr
, tsk
);
268 #ifndef CONFIG_SYSCTL
269 #ifdef CONFIG_PROCESS_DEBUG
270 printk("User process fault: interruption code 0x%lX\n",
275 if (sysctl_userprocess_debug
) {
276 printk("User process fault: interruption code 0x%lX\n",
282 const struct exception_table_entry
*fixup
;
283 fixup
= search_exception_tables(regs
->psw
.addr
& PSW_ADDR_INSN
);
285 regs
->psw
.addr
= fixup
->fixup
| PSW_ADDR_AMODE
;
287 die(str
, regs
, interruption_code
);
291 static inline void *get_check_address(struct pt_regs
*regs
)
293 return (void *)((regs
->psw
.addr
-S390_lowcore
.pgm_ilc
) & PSW_ADDR_INSN
);
296 static int do_debugger_trap(struct pt_regs
*regs
)
298 if ((regs
->psw
.mask
& PSW_MASK_PSTATE
) &&
299 (current
->ptrace
& PT_PTRACED
)) {
300 force_sig(SIGTRAP
,current
);
306 #define DO_ERROR(signr, str, name) \
307 asmlinkage void name(struct pt_regs * regs, long interruption_code) \
309 do_trap(interruption_code, signr, str, regs, NULL); \
312 #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
313 asmlinkage void name(struct pt_regs * regs, long interruption_code) \
316 info.si_signo = signr; \
318 info.si_code = sicode; \
319 info.si_addr = (void *)siaddr; \
320 do_trap(interruption_code, signr, str, regs, &info); \
323 DO_ERROR(SIGSEGV
, "Unknown program exception", default_trap_handler
)
325 DO_ERROR_INFO(SIGBUS
, "addressing exception", addressing_exception
,
326 BUS_ADRERR
, get_check_address(regs
))
327 DO_ERROR_INFO(SIGILL
, "execute exception", execute_exception
,
328 ILL_ILLOPN
, get_check_address(regs
))
329 DO_ERROR_INFO(SIGFPE
, "fixpoint divide exception", divide_exception
,
330 FPE_INTDIV
, get_check_address(regs
))
331 DO_ERROR_INFO(SIGILL
, "operand exception", operand_exception
,
332 ILL_ILLOPN
, get_check_address(regs
))
333 DO_ERROR_INFO(SIGILL
, "privileged operation", privileged_op
,
334 ILL_PRVOPC
, get_check_address(regs
))
335 DO_ERROR_INFO(SIGILL
, "special operation exception", special_op_exception
,
336 ILL_ILLOPN
, get_check_address(regs
))
337 DO_ERROR_INFO(SIGILL
, "translation exception", translation_exception
,
338 ILL_ILLOPN
, get_check_address(regs
))
341 do_fp_trap(struct pt_regs
*regs
, void *location
,
342 int fpc
, long interruption_code
)
346 si
.si_signo
= SIGFPE
;
348 si
.si_addr
= location
;
350 /* FPC[2] is Data Exception Code */
351 if ((fpc
& 0x00000300) == 0) {
352 /* bits 6 and 7 of DXC are 0 iff IEEE exception */
353 if (fpc
& 0x8000) /* invalid fp operation */
354 si
.si_code
= FPE_FLTINV
;
355 else if (fpc
& 0x4000) /* div by 0 */
356 si
.si_code
= FPE_FLTDIV
;
357 else if (fpc
& 0x2000) /* overflow */
358 si
.si_code
= FPE_FLTOVF
;
359 else if (fpc
& 0x1000) /* underflow */
360 si
.si_code
= FPE_FLTUND
;
361 else if (fpc
& 0x0800) /* inexact */
362 si
.si_code
= FPE_FLTRES
;
364 current
->thread
.ieee_instruction_pointer
= (addr_t
) location
;
365 do_trap(interruption_code
, SIGFPE
,
366 "floating point exception", regs
, &si
);
369 asmlinkage
void illegal_op(struct pt_regs
* regs
, long interruption_code
)
375 location
= (__u16
*) get_check_address(regs
);
378 * We got all needed information from the lowcore and can
379 * now safely switch on interrupts.
381 if (regs
->psw
.mask
& PSW_MASK_PSTATE
)
384 if (regs
->psw
.mask
& PSW_MASK_PSTATE
)
385 get_user(*((__u16
*) opcode
), location
);
387 *((__u16
*)opcode
)=*((__u16
*)location
);
388 if (*((__u16
*)opcode
)==S390_BREAKPOINT_U16
)
390 if(do_debugger_trap(regs
))
393 #ifdef CONFIG_MATHEMU
394 else if (regs
->psw
.mask
& PSW_MASK_PSTATE
)
396 if (opcode
[0] == 0xb3) {
397 get_user(*((__u16
*) (opcode
+2)), location
+1);
398 signal
= math_emu_b3(opcode
, regs
);
399 } else if (opcode
[0] == 0xed) {
400 get_user(*((__u32
*) (opcode
+2)),
401 (__u32
*)(location
+1));
402 signal
= math_emu_ed(opcode
, regs
);
403 } else if (*((__u16
*) opcode
) == 0xb299) {
404 get_user(*((__u16
*) (opcode
+2)), location
+1);
405 signal
= math_emu_srnm(opcode
, regs
);
406 } else if (*((__u16
*) opcode
) == 0xb29c) {
407 get_user(*((__u16
*) (opcode
+2)), location
+1);
408 signal
= math_emu_stfpc(opcode
, regs
);
409 } else if (*((__u16
*) opcode
) == 0xb29d) {
410 get_user(*((__u16
*) (opcode
+2)), location
+1);
411 signal
= math_emu_lfpc(opcode
, regs
);
418 if (signal
== SIGFPE
)
419 do_fp_trap(regs
, location
,
420 current
->thread
.fp_regs
.fpc
, interruption_code
);
422 do_trap(interruption_code
, signal
,
423 "illegal operation", regs
, NULL
);
427 #ifdef CONFIG_MATHEMU
429 specification_exception(struct pt_regs
* regs
, long interruption_code
)
432 __u16
*location
= NULL
;
435 location
= (__u16
*) get_check_address(regs
);
438 * We got all needed information from the lowcore and can
439 * now safely switch on interrupts.
441 if (regs
->psw
.mask
& PSW_MASK_PSTATE
)
444 if (regs
->psw
.mask
& PSW_MASK_PSTATE
) {
445 get_user(*((__u16
*) opcode
), location
);
447 case 0x28: /* LDR Rx,Ry */
448 signal
= math_emu_ldr(opcode
);
450 case 0x38: /* LER Rx,Ry */
451 signal
= math_emu_ler(opcode
);
453 case 0x60: /* STD R,D(X,B) */
454 get_user(*((__u16
*) (opcode
+2)), location
+1);
455 signal
= math_emu_std(opcode
, regs
);
457 case 0x68: /* LD R,D(X,B) */
458 get_user(*((__u16
*) (opcode
+2)), location
+1);
459 signal
= math_emu_ld(opcode
, regs
);
461 case 0x70: /* STE R,D(X,B) */
462 get_user(*((__u16
*) (opcode
+2)), location
+1);
463 signal
= math_emu_ste(opcode
, regs
);
465 case 0x78: /* LE R,D(X,B) */
466 get_user(*((__u16
*) (opcode
+2)), location
+1);
467 signal
= math_emu_le(opcode
, regs
);
475 if (signal
== SIGFPE
)
476 do_fp_trap(regs
, location
,
477 current
->thread
.fp_regs
.fpc
, interruption_code
);
480 info
.si_signo
= signal
;
482 info
.si_code
= ILL_ILLOPN
;
483 info
.si_addr
= location
;
484 do_trap(interruption_code
, signal
,
485 "specification exception", regs
, &info
);
489 DO_ERROR_INFO(SIGILL
, "specification exception", specification_exception
,
490 ILL_ILLOPN
, get_check_address(regs
));
493 asmlinkage
void data_exception(struct pt_regs
* regs
, long interruption_code
)
498 location
= (__u16
*) get_check_address(regs
);
501 * We got all needed information from the lowcore and can
502 * now safely switch on interrupts.
504 if (regs
->psw
.mask
& PSW_MASK_PSTATE
)
507 if (MACHINE_HAS_IEEE
)
508 __asm__
volatile ("stfpc %0\n\t"
509 : "=m" (current
->thread
.fp_regs
.fpc
));
511 #ifdef CONFIG_MATHEMU
512 else if (regs
->psw
.mask
& PSW_MASK_PSTATE
) {
514 get_user(*((__u16
*) opcode
), location
);
516 case 0x28: /* LDR Rx,Ry */
517 signal
= math_emu_ldr(opcode
);
519 case 0x38: /* LER Rx,Ry */
520 signal
= math_emu_ler(opcode
);
522 case 0x60: /* STD R,D(X,B) */
523 get_user(*((__u16
*) (opcode
+2)), location
+1);
524 signal
= math_emu_std(opcode
, regs
);
526 case 0x68: /* LD R,D(X,B) */
527 get_user(*((__u16
*) (opcode
+2)), location
+1);
528 signal
= math_emu_ld(opcode
, regs
);
530 case 0x70: /* STE R,D(X,B) */
531 get_user(*((__u16
*) (opcode
+2)), location
+1);
532 signal
= math_emu_ste(opcode
, regs
);
534 case 0x78: /* LE R,D(X,B) */
535 get_user(*((__u16
*) (opcode
+2)), location
+1);
536 signal
= math_emu_le(opcode
, regs
);
539 get_user(*((__u16
*) (opcode
+2)), location
+1);
540 signal
= math_emu_b3(opcode
, regs
);
543 get_user(*((__u32
*) (opcode
+2)),
544 (__u32
*)(location
+1));
545 signal
= math_emu_ed(opcode
, regs
);
548 if (opcode
[1] == 0x99) {
549 get_user(*((__u16
*) (opcode
+2)), location
+1);
550 signal
= math_emu_srnm(opcode
, regs
);
551 } else if (opcode
[1] == 0x9c) {
552 get_user(*((__u16
*) (opcode
+2)), location
+1);
553 signal
= math_emu_stfpc(opcode
, regs
);
554 } else if (opcode
[1] == 0x9d) {
555 get_user(*((__u16
*) (opcode
+2)), location
+1);
556 signal
= math_emu_lfpc(opcode
, regs
);
566 if (current
->thread
.fp_regs
.fpc
& FPC_DXC_MASK
)
570 if (signal
== SIGFPE
)
571 do_fp_trap(regs
, location
,
572 current
->thread
.fp_regs
.fpc
, interruption_code
);
575 info
.si_signo
= signal
;
577 info
.si_code
= ILL_ILLOPN
;
578 info
.si_addr
= location
;
579 do_trap(interruption_code
, signal
,
580 "data exception", regs
, &info
);
586 /* init is done in lowcore.S and head.S */
588 void __init
trap_init(void)
592 for (i
= 0; i
< 128; i
++)
593 pgm_check_table
[i
] = &default_trap_handler
;
594 pgm_check_table
[1] = &illegal_op
;
595 pgm_check_table
[2] = &privileged_op
;
596 pgm_check_table
[3] = &execute_exception
;
597 pgm_check_table
[4] = &do_protection_exception
;
598 pgm_check_table
[5] = &addressing_exception
;
599 pgm_check_table
[6] = &specification_exception
;
600 pgm_check_table
[7] = &data_exception
;
601 pgm_check_table
[9] = ÷_exception
;
602 pgm_check_table
[0x10] = &do_segment_exception
;
603 pgm_check_table
[0x11] = &do_page_exception
;
604 pgm_check_table
[0x10] = &do_segment_exception
;
605 pgm_check_table
[0x11] = &do_page_exception
;
606 pgm_check_table
[0x12] = &translation_exception
;
607 pgm_check_table
[0x13] = &special_op_exception
;
608 #ifndef CONFIG_ARCH_S390X
609 pgm_check_table
[0x14] = &do_pseudo_page_fault
;
610 #else /* CONFIG_ARCH_S390X */
611 pgm_check_table
[0x38] = &addressing_exception
;
612 pgm_check_table
[0x3B] = &do_region_exception
;
613 #endif /* CONFIG_ARCH_S390X */
614 pgm_check_table
[0x15] = &operand_exception
;
615 pgm_check_table
[0x1C] = &privileged_op
;
618 * First try to get pfault pseudo page faults going.
619 * If this isn't available turn on pagex page faults.
622 /* request the 0x2603 external interrupt */
623 if (register_early_external_interrupt(0x2603, pfault_interrupt
,
624 &ext_int_pfault
) != 0)
625 panic("Couldn't request external interrupt 0x2603");
627 if (pfault_init() == 0)
630 /* Tough luck, no pfault. */
631 unregister_early_external_interrupt(0x2603, pfault_interrupt
,
634 #ifndef CONFIG_ARCH_S390X
635 cpcmd("SET PAGEX ON", NULL
, 0);
641 void handle_per_exception(struct pt_regs
*regs
)
643 if (regs
->psw
.mask
& PSW_MASK_PSTATE
) {
644 per_struct
*per_info
=¤t
->thread
.per_info
;
645 per_info
->lowcore
.words
.perc_atmid
=S390_lowcore
.per_perc_atmid
;
646 per_info
->lowcore
.words
.address
=S390_lowcore
.per_address
;
647 per_info
->lowcore
.words
.access_id
=S390_lowcore
.per_access_id
;
649 if (do_debugger_trap(regs
)) {
650 /* I've seen this possibly a task structure being reused ? */
651 printk("Spurious per exception detected\n");
652 printk("switching off per tracing for this task.\n");
654 /* Hopefully switching off per tracing will help us survive */
655 regs
->psw
.mask
&= ~PSW_MASK_PER
;